├── .gitignore
├── assets
├── images
│ ├── favicon.ico
│ └── jermass.png
├── fonts
│ ├── ubuntu-v15-latin-700.woff
│ ├── ubuntu-v15-latin-700.woff2
│ ├── ubuntu-v15-latin-regular.woff
│ └── ubuntu-v15-latin-regular.woff2
└── css
│ └── styles.scss
├── _plugins
├── numbers_in_words
│ ├── version.rb
│ ├── parsing
│ │ ├── parse_status.rb
│ │ ├── fraction_parsing.rb
│ │ ├── parse_fractions.rb
│ │ ├── pair_parsing.rb
│ │ ├── parse_individual_number.rb
│ │ ├── special.rb
│ │ ├── to_number.rb
│ │ └── number_parser.rb
│ ├── duck_punch.rb
│ ├── powers_of_ten.rb
│ ├── number_group.rb
│ ├── to_word.rb
│ ├── writer.rb
│ ├── exceptional_numbers.rb
│ └── fraction.rb
├── num2words-jekyll.rb
├── capitalize_all.rb
├── numbers_in_words.rb
└── humanize.rb
├── _site
└── _headers
├── _includes
├── index.js
├── bundle.js
└── package-lock.json
├── README.md
├── Gemfile
├── _config.yml
├── Gemfile.lock
├── _data
└── debt.csv
├── scripts.js
├── index.html
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 | .sass-cache
3 | .jekyll-cache
4 | .jekyll-metadata
5 | vendor
6 |
--------------------------------------------------------------------------------
/assets/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JermaSites/JermaDebt/HEAD/assets/images/favicon.ico
--------------------------------------------------------------------------------
/assets/images/jermass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JermaSites/JermaDebt/HEAD/assets/images/jermass.png
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module NumbersInWords
4 | VERSION = '1.0.1'
5 | end
6 |
--------------------------------------------------------------------------------
/_site/_headers:
--------------------------------------------------------------------------------
1 | /*
2 | Permissions-Policy: browsing-topics=()
3 |
4 | https://:debt.pages.dev/*
5 | X-Robots-Tag: noindex
6 |
--------------------------------------------------------------------------------
/assets/fonts/ubuntu-v15-latin-700.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JermaSites/JermaDebt/HEAD/assets/fonts/ubuntu-v15-latin-700.woff
--------------------------------------------------------------------------------
/assets/fonts/ubuntu-v15-latin-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JermaSites/JermaDebt/HEAD/assets/fonts/ubuntu-v15-latin-700.woff2
--------------------------------------------------------------------------------
/assets/fonts/ubuntu-v15-latin-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JermaSites/JermaDebt/HEAD/assets/fonts/ubuntu-v15-latin-regular.woff
--------------------------------------------------------------------------------
/assets/fonts/ubuntu-v15-latin-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JermaSites/JermaDebt/HEAD/assets/fonts/ubuntu-v15-latin-regular.woff2
--------------------------------------------------------------------------------
/_plugins/num2words-jekyll.rb:
--------------------------------------------------------------------------------
1 | require_relative 'numbers_in_words'
2 |
3 | module Jekyll
4 |
5 | module NumberWordsJekyll
6 | def num2words(value)
7 | return NumbersInWords.in_words(value)
8 | end
9 | end
10 |
11 | end
12 |
13 | Liquid::Template.register_filter(Jekyll::NumberWordsJekyll)
14 |
--------------------------------------------------------------------------------
/_plugins/capitalize_all.rb:
--------------------------------------------------------------------------------
1 | require 'liquid'
2 | require 'uri'
3 |
4 | # Capitalize all words of the input
5 | module Jekyll
6 | module CapitalizeAll
7 | def capitalize_all(words)
8 | return words.split(' ').map(&:capitalize).join(' ').gsub(/(?<=-)\w/, &:upcase)
9 | end
10 | end
11 | end
12 |
13 | Liquid::Template.register_filter(Jekyll::CapitalizeAll)
--------------------------------------------------------------------------------
/_includes/index.js:
--------------------------------------------------------------------------------
1 | import { Flip } from 'number-flip'
2 | var debt = parseInt((document.getElementById("debtCounterNum").innerHTML.slice(1)).replace(/,/g, ''));
3 | document.getElementById("debtCounterNum").innerHTML = "$";
4 | new Flip({
5 | node: document.getElementById("debtCounterNum"),
6 | from: 0,
7 | to: debt,
8 | separator: ',',
9 | duration: 2 // second
10 | })
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/parsing/parse_status.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module NumbersInWords
4 | class ParseStatus
5 | attr_accessor :reset, :memory, :answer
6 |
7 | def initialize
8 | @reset = true
9 | @memory = 0
10 | @answer = 0
11 | end
12 |
13 | def calculate
14 | answer + memory
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/duck_punch.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module NumbersInWords
4 | module NumericExtension
5 | def in_words(fraction: false)
6 | NumbersInWords::ToWord.new(self).in_words(fraction: fraction)
7 | end
8 | end
9 |
10 | module StringExtension
11 | def in_numbers(only_compress: false)
12 | NumbersInWords::ToNumber.new(self, only_compress).call
13 | end
14 | end
15 | end
16 |
17 | class String
18 | include NumbersInWords::StringExtension
19 | end
20 |
21 | class Numeric
22 | include NumbersInWords::NumericExtension
23 | end
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JermaDebt
2 |
3 | Website to track Jerma985's Debt to chat
4 |
5 | Make a PR or File an Issue if you want something changed! :)
6 |
7 | ### To change the debt
8 |
9 | Submit a PR with a new entry in `_data/debt.csv`
10 |
11 | `DebtChange` is the amount to change it by (negative is down)
12 |
13 | **Please ensure this is a number and not a string (no quotation marks, commas or any non-numerical values)**
14 |
15 | `Date` is a short date corresponding to when the change happened in the format of `Jan. 1st, 1970`
16 |
17 | `Reason` is a very short summary to be used on graphs and the like.
18 |
19 | `ReasonMarkdown` is a longer summary with markdown support to add citation URLs.
20 |
21 | `Active` is set to `FALSE` when an item that was previously added to the site has since been overruled. It is only here for historical purposes, any other time it should be set to `TRUE`.
22 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/parsing/fraction_parsing.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module NumbersInWords
4 | module FractionParsing
5 | def fraction(text)
6 | return unless possible_fraction?(text)
7 |
8 | NumbersInWords.exceptional_numbers.lookup_fraction(text)
9 | end
10 |
11 | def strip_punctuation(text)
12 | text = text.downcase.gsub(/[^a-z 0-9]/, ' ')
13 | to_remove = true
14 |
15 | to_remove = text.gsub! ' ', ' ' while to_remove
16 |
17 | text
18 | end
19 |
20 | def possible_fraction?(text)
21 | words = text.split(' ')
22 | result = words & NumbersInWords.exceptional_numbers.fraction_names
23 | result.length.positive?
24 | end
25 |
26 | def text_including_punctuation
27 | to_s.strip
28 | end
29 |
30 | def text
31 | strip_punctuation text_including_punctuation
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/parsing/parse_fractions.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module NumbersInWords
4 | class ParseFractions
5 | attr_reader :nums
6 |
7 | def initialize(nums)
8 | @nums = nums.map(&:to_f)
9 | end
10 |
11 | def call
12 | return if no_fractions?
13 |
14 | just_fraction || calculate
15 | end
16 |
17 | def calculate
18 | (parse(numbers) * parse(fractions)).rationalize(EPSILON).to_f
19 | end
20 |
21 | def parse(numbers)
22 | NumberParser.new.parse(numbers)
23 | end
24 |
25 | def numbers
26 | nums[0..index_of_fraction - 1]
27 | end
28 |
29 | def fractions
30 | nums[index_of_fraction..-1]
31 | end
32 |
33 | def just_fraction
34 | return nums.first if index_of_fraction.zero?
35 | end
36 |
37 | def index_of_fraction
38 | nums.index { |n| n < 1.0 }
39 | end
40 |
41 | def no_fractions?
42 | nums.all? { |n| n.zero? || n >= 1.0 }
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 | # Hello! This is where you manage which Jekyll version is used to run.
3 | # When you want to use a different version, change it below, save the
4 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
5 | #
6 | # bundle exec jekyll serve
7 | #
8 | # This will help ensure the proper Jekyll version is running.
9 | # Happy Jekylling!
10 | gem "jekyll"
11 | # This is the default theme for new Jekyll sites. You may change this to anything you like.
12 | gem "minima"
13 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
14 | # uncomment the line below. To upgrade, run `bundle update github-pages`.
15 | # gem "github-pages", group: :jekyll_plugins
16 | # If you have any plugins, put them here!
17 | # group :jekyll_plugins do
18 | # gem "jekyll-feed",
19 | # end
20 |
21 | # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
22 | # and associated library.
23 | platforms :mingw, :x64_mingw, :mswin, :jruby do
24 | gem "tzinfo"
25 | gem "tzinfo-data"
26 | end
27 |
28 | # Performance-booster for watching directories on Windows
29 | gem "wdm", :platforms => [:mingw, :x64_mingw, :mswin]
30 |
31 | gem 'eventmachine' #needed for windows live reloading?
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/parsing/pair_parsing.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module NumbersInWords
4 | class PairParsing
5 | attr_accessor :ints
6 | attr_reader :only_compress
7 |
8 | def initialize(ints, only_compress)
9 | @ints = ints
10 | @only_compress = only_compress
11 | end
12 |
13 | # 15,16
14 | # 85,16
15 | def pair_parse
16 | ints = compressed
17 | return ints if only_compress
18 |
19 | return ints[0] if ints.length == 1
20 |
21 | sum = 0
22 |
23 | ints.each do |n|
24 | sum *= n >= 10 ? 100 : 10
25 | sum += n
26 | end
27 |
28 | sum
29 | end
30 |
31 | private
32 |
33 | # [40, 2] => [42]
34 | def compressed
35 | return [] if ints.empty?
36 |
37 | result = []
38 | index = 0
39 |
40 | index, result = compress_numbers(result, index)
41 |
42 | result << ints[-1] if index < ints.length
43 |
44 | result
45 | end
46 |
47 | def compress_numbers(result, index)
48 | while index < ints.length - 1
49 | int, jump = compress_int(ints[index], ints[index + 1])
50 | result << int
51 | index += jump
52 | end
53 |
54 | [index, result]
55 | end
56 |
57 | def compress_int(int, next_int)
58 | tens = (int % 10).zero? && int > 10
59 | return [int + next_int, 2] if tens && next_int < 10
60 |
61 | [int, 1]
62 | end
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/powers_of_ten.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module NumbersInWords
4 | GOOGOL = 10**100
5 |
6 | POWERS_OF_TEN = {
7 | 0 => 'one',
8 | 1 => 'ten',
9 | 2 => 'hundred',
10 | 1 * 3 => 'thousand',
11 | 2 * 3 => 'million',
12 | 3 * 3 => 'billion',
13 | 4 * 3 => 'trillion',
14 | 5 * 3 => 'quadrillion',
15 | 6 * 3 => 'quintillion',
16 | 7 * 3 => 'sextillion',
17 | 8 * 3 => 'septillion',
18 | 9 * 3 => 'octillion',
19 | 10 * 3 => 'nonillion',
20 | 11 * 3 => 'decillion',
21 | 12 * 3 => 'undecillion',
22 | 13 * 3 => 'duodecillion',
23 | 14 * 3 => 'tredecillion',
24 | 15 * 3 => 'quattuordecillion',
25 | 16 * 3 => 'quindecillion',
26 | 17 * 3 => 'sexdecillion',
27 | 18 * 3 => 'septendecillion',
28 | 19 * 3 => 'octodecillion',
29 | 20 * 3 => 'novemdecillion',
30 | 21 * 3 => 'vigintillion',
31 | 22 * 3 => 'unvigintillion',
32 | 23 * 3 => 'duovigintillion',
33 | 24 * 3 => 'trevigintillion',
34 | 25 * 3 => 'quattuorvigintillion',
35 | 26 * 3 => 'quinvigintillion',
36 | 27 * 3 => 'sexvigintillion',
37 | 28 * 3 => 'septenvigintillion',
38 | 29 * 3 => 'octovigintillion',
39 | 30 * 3 => 'novemvigintillion',
40 | 31 * 3 => 'trigintillion',
41 | 32 * 3 => 'untrigintillion',
42 | 33 * 3 => 'duotrigintillion',
43 | 100 => 'googol',
44 | 101 * 3 => 'centillion',
45 | GOOGOL => 'googolplex'
46 | }.freeze
47 |
48 | POWERS_RX = Regexp.union(POWERS_OF_TEN.values[1..-1]).freeze
49 | end
50 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/parsing/parse_individual_number.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module NumbersInWords
4 | class ParseIndividualNumber
5 | extend Forwardable
6 | def_delegators :parse_status, :reset=, :memory=, :answer=, :reset, :memory, :answer
7 |
8 | attr_reader :parse_status, :num
9 |
10 | def initialize(parse_status, num)
11 | @parse_status = parse_status
12 | @num = num
13 | end
14 |
15 | def call
16 | if reset
17 | clear
18 | else
19 | handle_power_of_ten
20 |
21 | update_memory
22 | end
23 |
24 | [reset, memory, answer]
25 | end
26 |
27 | private
28 |
29 | def clear
30 | self.reset = false
31 | self.memory += num
32 | end
33 |
34 | def handle_power_of_ten
35 | # x4. multiply memory by 10^9 because memory < power of ten
36 | return unless power_of_ten?(num)
37 | return unless power_of_ten(num) > 2
38 |
39 | self.memory *= num
40 | # 17. add memory to answer (and reset) (memory pow of ten > 2)
41 | self.answer += memory
42 | self.memory = 0
43 | self.reset = true
44 | end
45 |
46 | def update_memory
47 | self.memory = new_memory
48 | end
49 |
50 | def new_memory
51 | if memory < num
52 | memory * num
53 | else
54 | memory + num
55 | end
56 | end
57 |
58 | def power_of_ten(integer)
59 | Math.log10(integer)
60 | end
61 |
62 | def power_of_ten?(integer)
63 | return true if integer.zero?
64 |
65 | power_of_ten(integer) == power_of_ten(integer).to_i
66 | end
67 | end
68 | end
69 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | # Welcome to Jekyll!
2 | #
3 | # This config file is meant for settings that affect your whole blog, values
4 | # which you are expected to set up once and rarely edit after that. If you find
5 | # yourself editing this file very often, consider using Jekyll's data files
6 | # feature for the data you need to update frequently.
7 | #
8 | # For technical reasons, this file is *NOT* reloaded automatically when you use
9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process.
10 | #
11 | # If you need help with YAML syntax, here are some quick references for you:
12 | # https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml
13 | # https://learnxinyminutes.com/docs/yaml/
14 | #
15 | # Site settings
16 | # These are used to personalize your new site. If you look in the HTML files,
17 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
18 | # You can create any custom variable you would like, and they will be accessible
19 | # in the templates via {{ site.myvariable }}.
20 |
21 | # Exclude from processing.
22 | # The following items will not be processed, by default.
23 | # Any item listed under the `exclude:` key here will be automatically added to
24 | # the internal "default list".
25 | #
26 | # Excluded items can be processed by explicitly listing the directories or
27 | # their entries' file path in the `include:` list.
28 | #
29 | # exclude:
30 | # - .sass-cache/
31 | # - .jekyll-cache/
32 | # - gemfiles/
33 | # - Gemfile
34 | # - Gemfile.lock
35 | # - node_modules/
36 | # - vendor/bundle/
37 | # - vendor/cache/
38 | # - vendor/gems/
39 | # - vendor/ruby/
40 |
41 | include:
42 | - _data/
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/parsing/special.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative './fraction_parsing'
4 |
5 | module NumbersInWords
6 | class Special
7 | extend Forwardable
8 | def_delegator :that, :to_s
9 |
10 | include FractionParsing
11 |
12 | attr_reader :that, :only_compress
13 |
14 | def initialize(that, only_compress)
15 | @that = that
16 | @only_compress = only_compress
17 | end
18 |
19 | def call
20 | float ||
21 | negative ||
22 | fraction(that) ||
23 | mixed_words_and_digits ||
24 | one
25 | end
26 |
27 | def float
28 | text_including_punctuation.to_f if text =~ /^-?\d+(.\d+)?$/
29 | end
30 |
31 | def negative
32 | stripped = strip_minus text
33 | return unless stripped
34 |
35 | stripped_n = NumbersInWords.in_numbers(stripped, only_compress: only_compress)
36 | only_compress ? stripped_n.map { |k| k * -1 } : -1 * stripped_n
37 | end
38 |
39 | def mixed_words_and_digits
40 | return unless numeric?(that)
41 |
42 | in_words = that.split(' ').map { |word| numeric?(word) ? NumbersInWords.in_words(word) : word }.join(' ')
43 | ToNumber.new(in_words, only_compress).call
44 | end
45 |
46 | def numeric?(word)
47 | word.match(/\d+/)
48 | end
49 |
50 | def strip_minus(txt)
51 | txt.gsub(/^minus/, '') if txt =~ /^minus/
52 | end
53 |
54 | def one
55 | one = check_one text
56 |
57 | return unless one
58 |
59 | res = NumbersInWords.in_numbers(one[1])
60 | only_compress ? [res] : res
61 | end
62 |
63 | def check_one(txt)
64 | txt.match(/^one (#{POWERS_RX})$/)
65 | end
66 | end
67 | end
68 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative 'numbers_in_words/version'
4 | require_relative 'numbers_in_words/exceptional_numbers'
5 | require_relative 'numbers_in_words/parsing/number_parser'
6 | require_relative 'numbers_in_words/to_word'
7 | require_relative 'numbers_in_words/parsing/to_number'
8 |
9 | module NumbersInWords
10 | LENGTH_OF_GOOGOL = 101 # length of the string i.e. one with 100 zeros
11 | Error = ::Class.new(::StandardError)
12 | AmbiguousParsingError = ::Class.new(Error)
13 | DivideByZeroError = ::Class.new(Error)
14 | InvalidNumber = ::Class.new(Error)
15 |
16 | class << self
17 | extend Forwardable
18 | def_delegators :exceptional_numbers, :fraction
19 |
20 | def in_words(num, fraction: false)
21 | ToWord.new(num).in_words(fraction: fraction)
22 | end
23 |
24 | def in_numbers(words, only_compress: false)
25 | ToNumber.new(words, only_compress).call
26 | end
27 |
28 | def exceptional_numbers
29 | @exceptional_numbers ||= ExceptionalNumbers.new
30 | end
31 |
32 | def lookup(number)
33 | exceptional_numbers.lookup(number)
34 | end
35 |
36 | def exceptional_number(text)
37 | exceptional_numbers_to_i[text]
38 | end
39 |
40 | def power_of_ten(text)
41 | powers_of_ten_to_i[text]
42 | end
43 |
44 | private
45 |
46 | def exceptional_numbers_to_i
47 | @exceptional_numbers_to_i ||= swap_keys exceptional_numbers.to_h
48 | end
49 |
50 | def powers_of_ten_to_i
51 | @powers_of_ten_to_i ||= swap_keys POWERS_OF_TEN
52 | end
53 |
54 | def swap_keys(hash)
55 | hash.each_with_object({}) { |(k, v), h| h[v] = k }
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/parsing/to_number.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative './special'
4 | require_relative './fraction_parsing'
5 |
6 | module NumbersInWords
7 | class ToNumber
8 | include FractionParsing
9 | extend Forwardable
10 | def_delegator :that, :to_s
11 |
12 | attr_reader :that, :only_compress
13 |
14 | def initialize(that, only_compress)
15 | @that = that
16 | @only_compress = only_compress
17 | end
18 |
19 | def call
20 | special || decimal || as_numbers
21 | end
22 |
23 | private
24 |
25 | def special
26 | Special.new(that, only_compress).call
27 | end
28 |
29 | def decimal
30 | match = check_decimal text
31 | return unless match
32 |
33 | integer = NumbersInWords.in_numbers(match.pre_match)
34 | decimal = NumbersInWords.in_numbers(match.post_match)
35 | integer + "0.#{decimal}".to_f
36 | end
37 |
38 | def as_numbers
39 | numbers = word_array_to_nums text.split(' ')
40 |
41 | NumbersInWords::NumberParser.new.parse numbers, only_compress: only_compress
42 | end
43 |
44 | def word_array_to_nums(words)
45 | words.map { |i| word_to_num(i) }.compact
46 | end
47 |
48 | # handles simple single word numbers
49 | # e.g. one, seven, twenty, eight, thousand etc
50 | def word_to_num(word)
51 | text = canonize(word.to_s.chomp.strip)
52 |
53 | NumbersInWords.exceptional_number(text) || fraction(text) || power(text)
54 | end
55 |
56 | def power(text)
57 | power = NumbersInWords.power_of_ten(text)
58 |
59 | 10**power if power
60 | end
61 |
62 | def canonize(word)
63 | aliases[word] || word
64 | end
65 |
66 | def aliases
67 | {
68 | 'a' => 'one',
69 | 'oh' => 'zero'
70 | }
71 | end
72 |
73 | def check_decimal(txt)
74 | txt.match(/\spoint\s/)
75 | end
76 | end
77 | end
78 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/number_group.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module NumbersInWords
4 | class NumberGroup
5 | include Enumerable
6 | attr_accessor :number
7 |
8 | def self.groups_of(number, size)
9 | new(number).groups(size)
10 | end
11 |
12 | def initialize(number)
13 | @number = number
14 | end
15 |
16 | # split into groups this gives us 1234567 => 123 456 7
17 | # so we need to reverse first
18 | # in stages
19 | def groups(size)
20 | # 1234567 => %w(765 432 1)
21 | @array = in_groups_of(@number.to_s.reverse.split(''), size)
22 | # %w(765 432 1) => %w(1 432 765)
23 | @array.reverse!
24 |
25 | # %w(1 432 765) => [1, 234, 567]
26 | @array.map! { |group| group.reverse.join('').to_i }
27 | @array.reverse! # put in ascending order of power of ten
28 |
29 | power = 0
30 |
31 | # [1, 234, 567] => {6 => 1, 3 => 234, 0 => 567}
32 | @array.each_with_object({}) do |digits, o|
33 | o[power] = digits
34 | power += size
35 | end
36 | end
37 |
38 | def split_decimals
39 | return unless @number.is_a? Float
40 |
41 | int, decimal = @number.to_s.split '.'
42 |
43 | [int.to_i, decimal.split(//).map(&:to_i)]
44 | end
45 |
46 | def split_googols
47 | googols = @number.to_s[0..-LENGTH_OF_GOOGOL].to_i
48 | remainder = @number.to_s[(1 - LENGTH_OF_GOOGOL)..-1].to_i
49 | [googols, remainder]
50 | end
51 |
52 | private
53 |
54 | def in_groups_of(array, number, fill_with = nil)
55 | # size % number gives how many extra we have;
56 | # subtracting from number gives how many to add;
57 | # modulo number ensures we don't add group of just fill.
58 | padding = (number - array.size % number) % number
59 | collection = array.dup.concat(Array.new(padding, fill_with))
60 |
61 | collection.each_slice(number).to_a
62 | end
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/to_word.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative 'writer'
4 | require_relative 'number_group'
5 | require_relative 'fraction'
6 |
7 | module NumbersInWords
8 | # Arbitrarily small number for rationalizing fractions
9 | EPSILON = 0.0000000001
10 |
11 | class ToWord
12 | attr_reader :that
13 |
14 | def initialize(that)
15 | @that = that
16 | end
17 |
18 | def to_i
19 | that.to_i
20 | end
21 |
22 | def negative
23 | return unless to_i.negative?
24 |
25 | 'minus ' + NumbersInWords.in_words(-@that)
26 | end
27 |
28 | def in_words(fraction: false)
29 | as_fraction(fraction) ||
30 | handle_exceptional_numbers ||
31 | decimals ||
32 | negative ||
33 | output
34 | end
35 |
36 | def as_fraction(fraction)
37 | return Fraction.in_words(that) if fraction
38 | end
39 |
40 | def decimals
41 | int, decimals = NumberGroup.new(@that).split_decimals
42 | return unless int
43 |
44 | out = NumbersInWords.in_words(int) + ' point '
45 | decimals.each do |decimal|
46 | out << NumbersInWords.in_words(decimal.to_i) + ' '
47 | end
48 | out.strip
49 | end
50 |
51 | def output
52 | output = if to_i.to_s.length == 2 # 20-99
53 | handle_tens(to_i)
54 | else
55 | Writer.new(that).call # longer numbers
56 | end
57 |
58 | output.strip
59 | end
60 |
61 | def handle_tens(number)
62 | output = ''
63 |
64 | tens = (number / 10).round * 10 # write the tens
65 |
66 | output += NumbersInWords.lookup(tens) # e.g. eighty
67 |
68 | digit = number - tens # write the digits
69 |
70 | unless digit.zero?
71 | join = number < 100 ? '-' : ' '
72 | output << join + NumbersInWords.in_words(digit)
73 | end
74 |
75 | output
76 | end
77 |
78 | def handle_exceptional_numbers
79 | return unless @that.is_a?(Integer)
80 |
81 | NumbersInWords.exceptional_numbers.lookup(@that)
82 | end
83 | end
84 | end
85 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/writer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module NumbersInWords
4 | class Writer
5 | def initialize(that)
6 | @that = that
7 | end
8 |
9 | def call
10 | length = @that.to_s.length
11 | output =
12 | if length == 3
13 | # e.g. 113 splits into "one hundred" and "thirteen"
14 | write_groups(2)
15 |
16 | # more than one hundred less than one googol
17 | elsif length < LENGTH_OF_GOOGOL
18 | write_groups(3)
19 |
20 | elsif length >= LENGTH_OF_GOOGOL
21 | write_googols
22 | end
23 | output.strip
24 | end
25 |
26 | def group_words(size)
27 | # 1000 and over Numbers are split into groups of three
28 | groups = NumberGroup.groups_of @that, size
29 | powers = groups.keys.sort.reverse # put in descending order
30 |
31 | powers.each do |power|
32 | name = NumbersInWords::POWERS_OF_TEN[power]
33 | digits = groups[power]
34 | yield power, name, digits
35 | end
36 | end
37 |
38 | private
39 |
40 | def write_googols
41 | googols, remainder = NumberGroup.new(@that).split_googols
42 | output = ''
43 |
44 | output = output + ' ' + NumbersInWords.in_words(googols) + ' googol'
45 | if remainder.positive?
46 | prefix = ' '
47 | prefix += 'and ' if remainder < 100
48 | output = output + prefix + NumbersInWords.in_words(remainder)
49 | end
50 |
51 | output
52 | end
53 |
54 | def write_groups(group)
55 | # e.g. 113 splits into "one hundred" and "thirteen"
56 | output = ''
57 | group_words(group) do |power, name, digits|
58 | output = output + ','
59 | if digits.positive?
60 | prefix = ' '
61 | # no and between thousands and hundreds
62 | prefix += 'and ' if power.zero? && (digits < 100)
63 | output = output + prefix + NumbersInWords.in_words(digits)
64 | output = output + prefix + name unless power.zero?
65 | end
66 | end
67 | output = output.gsub(/(?<=[a-zA-Z]), /, " ")
68 | output.gsub(" ,", ",")
69 | end
70 | end
71 | end
72 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | addressable (2.8.6)
5 | public_suffix (>= 2.0.2, < 6.0)
6 | colorator (1.1.0)
7 | concurrent-ruby (1.2.3)
8 | em-websocket (0.5.3)
9 | eventmachine (>= 0.12.9)
10 | http_parser.rb (~> 0)
11 | eventmachine (1.2.7)
12 | eventmachine (1.2.7-x64-mingw32)
13 | ffi (1.16.3)
14 | forwardable-extended (2.6.0)
15 | google-protobuf (3.25.2)
16 | http_parser.rb (0.8.0)
17 | i18n (1.14.1)
18 | concurrent-ruby (~> 1.0)
19 | jekyll (4.3.3)
20 | addressable (~> 2.4)
21 | colorator (~> 1.0)
22 | em-websocket (~> 0.5)
23 | i18n (~> 1.0)
24 | jekyll-sass-converter (>= 2.0, < 4.0)
25 | jekyll-watch (~> 2.0)
26 | kramdown (~> 2.3, >= 2.3.1)
27 | kramdown-parser-gfm (~> 1.0)
28 | liquid (~> 4.0)
29 | mercenary (>= 0.3.6, < 0.5)
30 | pathutil (~> 0.9)
31 | rouge (>= 3.0, < 5.0)
32 | safe_yaml (~> 1.0)
33 | terminal-table (>= 1.8, < 4.0)
34 | webrick (~> 1.7)
35 | jekyll-feed (0.17.0)
36 | jekyll (>= 3.7, < 5.0)
37 | jekyll-sass-converter (3.0.0)
38 | sass-embedded (~> 1.54)
39 | jekyll-seo-tag (2.8.0)
40 | jekyll (>= 3.8, < 5.0)
41 | jekyll-watch (2.2.1)
42 | listen (~> 3.0)
43 | kramdown (2.4.0)
44 | rexml
45 | kramdown-parser-gfm (1.1.0)
46 | kramdown (~> 2.0)
47 | liquid (4.0.4)
48 | listen (3.8.0)
49 | rb-fsevent (~> 0.10, >= 0.10.3)
50 | rb-inotify (~> 0.9, >= 0.9.10)
51 | mercenary (0.4.0)
52 | minima (2.5.1)
53 | jekyll (>= 3.5, < 5.0)
54 | jekyll-feed (~> 0.9)
55 | jekyll-seo-tag (~> 2.1)
56 | pathutil (0.16.2)
57 | forwardable-extended (~> 2.6)
58 | public_suffix (5.0.4)
59 | rb-fsevent (0.11.2)
60 | rb-inotify (0.10.1)
61 | ffi (~> 1.0)
62 | rexml (3.2.6)
63 | rouge (4.2.0)
64 | safe_yaml (1.0.5)
65 | sass-embedded (1.70.0-x64-mingw-ucrt)
66 | google-protobuf (~> 3.25)
67 | sass-embedded (1.70.0-x64-mingw32)
68 | google-protobuf (~> 3.25)
69 | sass-embedded (1.70.0-x86_64-linux-gnu)
70 | google-protobuf (~> 3.25)
71 | terminal-table (3.0.2)
72 | unicode-display_width (>= 1.1.1, < 3)
73 | tzinfo (2.0.6)
74 | concurrent-ruby (~> 1.0)
75 | tzinfo-data (1.2023.4)
76 | tzinfo (>= 1.0.0)
77 | unicode-display_width (2.5.0)
78 | wdm (0.1.1)
79 | webrick (1.8.1)
80 |
81 | PLATFORMS
82 | x64-mingw-ucrt
83 | x64-mingw32
84 | x86_64-linux
85 |
86 | DEPENDENCIES
87 | eventmachine
88 | jekyll
89 | minima
90 | tzinfo
91 | tzinfo-data
92 | wdm
93 |
94 | BUNDLED WITH
95 | 2.2.15
96 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/exceptional_numbers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'forwardable'
4 |
5 | require_relative 'fraction'
6 | require_relative 'powers_of_ten'
7 |
8 | module NumbersInWords
9 | class ExceptionalNumbers
10 | extend Forwardable
11 |
12 | DEFINITIONS = {
13 | 0 => { number: 'zero', ordinal: 'zeroth' },
14 | 1 => { number: 'one', ordinal: 'first' },
15 | 2 => { number: 'two', ordinal: 'second', fraction: { singular: 'half', plural: 'halves' } },
16 | 3 => { number: 'three', ordinal: 'third' },
17 | 4 => { number: 'four', ordinal: 'fourth', fraction: { singular: 'quarter', plural: 'quarters' } },
18 | 5 => { number: 'five', ordinal: 'fifth' },
19 | 6 => { number: 'six' },
20 | 7 => { number: 'seven' },
21 | 8 => { number: 'eight', ordinal: 'eighth' },
22 | 9 => { number: 'nine', ordinal: 'ninth' },
23 | 10 => { number: 'ten' },
24 | 11 => { number: 'eleven' },
25 | 12 => { number: 'twelve', ordinal: 'twelfth' },
26 | 13 => { number: 'thirteen' },
27 | 14 => { number: 'fourteen' },
28 | 15 => { number: 'fifteen' },
29 | 16 => { number: 'sixteen' },
30 | 17 => { number: 'seventeen' },
31 | 18 => { number: 'eighteen' },
32 | 19 => { number: 'nineteen' },
33 | 20 => { number: 'twenty', ordinal: 'twentieth' },
34 | 30 => { number: 'thirty', ordinal: 'thirtieth' },
35 | 40 => { number: 'forty', ordinal: 'fortieth' },
36 | 50 => { number: 'fifty', ordinal: 'fiftieth' },
37 | 60 => { number: 'sixty', ordinal: 'sixtieth' },
38 | 70 => { number: 'seventy', ordinal: 'seventieth' },
39 | 80 => { number: 'eighty', ordinal: 'eightieth' },
40 | 90 => { number: 'ninety', ordinal: 'ninetieth' }
41 | }.freeze
42 |
43 | def fraction_names
44 | @fraction_names ||= determine_fraction_names
45 | end
46 |
47 | def lookup_fraction(words)
48 | fraction_lookup[words]
49 | end
50 |
51 | def fraction_lookup
52 | @fraction_lookup ||= generate_fraction_lookup
53 | end
54 |
55 | def lookup(number)
56 | to_h[number]
57 | end
58 |
59 | def fraction(denominator: nil, numerator: nil, word: nil)
60 | raise unless denominator || word
61 |
62 | numerator ||= 1
63 |
64 | denominator ||= NumbersInWords.in_numbers(word)
65 |
66 | Fraction.new(denominator: denominator, numerator: numerator, attributes: DEFINITIONS[denominator])
67 | end
68 |
69 | def to_h
70 | @to_h ||= DEFINITIONS.transform_values do |h|
71 | h[:number]
72 | end
73 | end
74 |
75 | private
76 |
77 | def generate_fraction_lookup
78 | named_fractions.each_with_object({}) do |f, result|
79 | f.lookup_keys.each do |k|
80 | key = k.split(' ').last
81 | result[key] = 1.0 / f.denominator.to_f
82 | end
83 | end
84 | end
85 |
86 | def named_fractions
87 | @named_fractions ||= numbers.flat_map do |n|
88 | [
89 | Fraction.new(denominator: n, numerator: 1),
90 | Fraction.new(denominator: n, numerator: 2)
91 | ]
92 | end
93 | end
94 |
95 | def numbers
96 | (2..100).to_a + powers_of_ten_skipping_googolplex.map { |p| 10**p }
97 | end
98 |
99 | def powers_of_ten_skipping_googolplex
100 | POWERS_OF_TEN.keys[0..-2]
101 | end
102 |
103 | def determine_fraction_names
104 | names = named_fractions.map(&:in_words)
105 |
106 | words = names.map(&:split).map(&:last)
107 | words += strip_punctuation(words)
108 | words.uniq
109 | end
110 |
111 | def strip_punctuation(words)
112 | words.map { |w| w.gsub(/^a-z/, ' ') }
113 | end
114 | end
115 | end
116 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/fraction.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module NumbersInWords
4 | class Fraction
5 | attr_reader :denominator, :numerator, :attributes
6 |
7 | def self.in_words(that)
8 | r = that.rationalize(EPSILON)
9 |
10 | NumbersInWords
11 | .fraction(denominator: r.denominator, numerator: r.numerator)
12 | .in_words
13 | end
14 |
15 | def initialize(denominator:, numerator: 1, attributes: nil)
16 | @denominator = denominator
17 | @numerator = numerator
18 | @attributes = attributes || NumbersInWords::ExceptionalNumbers::DEFINITIONS[denominator] || {}
19 | end
20 |
21 | def lookup_keys
22 | key = in_words
23 | key2 = strip_punctuation(key.split(' ')).join(' ')
24 |
25 | key3 = "a #{key}"
26 | key4 = "an #{key}"
27 | key5 = "a #{key2}"
28 | key6 = "an #{key2}"
29 | [key, key2, key3, key4, key5, key6].uniq
30 | end
31 |
32 | def in_words
33 | NumbersInWords.in_words(numerator) + ' ' + fraction
34 | end
35 |
36 | def ordinal
37 | pluralize? ? pluralized_ordinal_in_words : singular_ordinal_in_words
38 | end
39 |
40 | def fraction
41 | if denominator == Float::INFINITY
42 | # We've reached the limits of ruby's number system
43 | # by the time we get to a googolplex (10 ** (10 ** 100))
44 | return pluralize? ? 'infinitieths' : 'infinitieth'
45 | end
46 |
47 | pluralize? ? pluralized_fraction : singular_fraction
48 | end
49 |
50 | private
51 |
52 | def strip_punctuation(words)
53 | words.map { |w| w.gsub(/^a-z/, ' ') }
54 | end
55 |
56 | def pluralized_fraction
57 | fraction_plural || pluralized_ordinal_in_words
58 | end
59 |
60 | def singular_fraction
61 | fraction_singular || singular_ordinal_in_words
62 | end
63 |
64 | def pluralized_ordinal_in_words
65 | pluralized_ordinal || denominator_ordinal_in_words
66 | end
67 |
68 | def singular_ordinal_in_words
69 | singular_ordinal || denominator_ordinal_in_words
70 | end
71 |
72 | def singular_ordinal
73 | attributes[:ordinal]
74 | end
75 |
76 | def pluralized_ordinal
77 | singular_ordinal && singular_ordinal + 's'
78 | end
79 |
80 | def pluralize?
81 | numerator > 1
82 | end
83 |
84 | def denominator_ordinal_in_words
85 | if denominator > 100
86 | # one hundred and second
87 | with_remainder(100, ' and ')
88 | elsif denominator > 19
89 | # two thirty-fifths
90 | with_remainder(10, '-')
91 | else
92 | # one seventh
93 | singular = NumbersInWords.in_words(denominator) + 'th'
94 | pluralize? ? singular + 's' : singular
95 | end
96 | end
97 |
98 | def with_remainder(mod, join_word)
99 | rest = denominator % mod
100 | main = denominator - rest
101 | main = NumbersInWords.in_words(main)
102 |
103 | main = main.gsub(/^one /, '') if pluralize?
104 |
105 | rest_zero(rest, main) || joined(main, rest, join_word)
106 | end
107 |
108 | def joined(main, rest, join_word)
109 | main +
110 | join_word +
111 | self.class.new(numerator: numerator, denominator: rest).ordinal
112 | end
113 |
114 | def rest_zero(rest, main)
115 | return unless rest.zero?
116 |
117 | if pluralize?
118 | main + 'ths'
119 | else
120 | main + 'th'
121 | end
122 | end
123 |
124 | def exception
125 | attributes[:fraction]
126 | end
127 |
128 | def fraction_singular
129 | exception && exception[:singular]
130 | end
131 |
132 | def fraction_plural
133 | exception && exception[:plural]
134 | end
135 | end
136 | end
137 |
--------------------------------------------------------------------------------
/_plugins/numbers_in_words/parsing/number_parser.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'forwardable'
4 | require_relative 'parse_fractions'
5 | require_relative 'parse_status'
6 | require_relative 'parse_individual_number'
7 | require_relative 'pair_parsing'
8 |
9 | module NumbersInWords
10 | class NumberParser
11 | # Example: 364,895,457,898
12 | # three hundred and sixty four billion eight hundred and ninety five million
13 | # four hundred and fifty seven thousand eight hundred and ninety eight
14 | #
15 | # 3 100 60 4 10^9, 8 100 90 5 10^6, 4 100 50 7 1000, 8 100 90 8
16 | # memory answer
17 | # x1. 3 add to memory because answer and memory are zero 3 0
18 | # x2. memory * 100 (because memory<100) 300 0
19 | # x3. 60 add to memory because memory > 60 360 0
20 | # x3. 4 add to memory because memory > 4 364 0
21 | # x4. multiply memory by 10^9 because memory < power of ten 364*10^9 0
22 | # x5. add memory to answer (and reset)memory > 8 (memory pow of ten > 2) 0 364*10^9
23 | # x6. 8 add to memory because not finished 8 ''
24 | # x7. multiply memory by 100 because memory < 100 800 ''
25 | # x8. add 90 to memory because memory > 90 890 ''
26 | # x9. add 5 to memory because memory > 5 895 ''
27 | # x10. multiply memory by 10^6 because memory < power of ten 895*10^6 ''
28 | # x11. add memory to answer (and reset) because memory power ten > 2 0 364895 * 10^6
29 | # x12. 4 add to memory because not finished 4 ''
30 | # x13. memory * 100 because memory < 100 400 ''
31 | # x14. memory + 50 because memory > 50 450 ''
32 | # x15. memory + 7 because memory > 7 457 ''
33 | # x16. memory * 1000 because memory < 1000 457000 ''
34 | # x17. add memory to answer (and reset)memory > 8 (memory pow of ten > 2) 0 364895457000
35 | # x18. 8 add to memory because not finished 8 ''
36 | # x19. memory * 100 because memory < 100 800 ''
37 | # x14. memory + 90 because memory > 90 890 ''
38 | # x15. memory + 8 because memory > 8 898 ''
39 | # 16. finished so add memory to answer
40 |
41 | # Example
42 | # 2001
43 | # two thousand and one
44 | # 2 1000 1
45 | # memory answer
46 | # 1. add 2 to memory because first 2 0
47 | # 2. multiply memory by 1000 because memory < 1000 2000 0
48 | # 3. add memory to answer,reset, because power of ten>2 0 2000
49 | # 4. add 1 to memory 1 2000
50 | # 5. finish - add memory to answer 0 2001
51 |
52 | SCALES_N = [10**2, 10**3, 10**6, 10**9, 10**12, 10**100].freeze
53 |
54 | def parse(nums, only_compress: false)
55 | fractions(nums) ||
56 | small_numbers(nums, only_compress) ||
57 | pair_parsing(nums, only_compress) ||
58 | parse_each(nums)
59 | end
60 |
61 | private
62 |
63 | def fractions(nums)
64 | ParseFractions.new(nums).call
65 | end
66 |
67 | # 7 0.066666666666667 => 0.46666666666666
68 |
69 | # 15 => 15
70 | def small_numbers(nums, only_compress)
71 | return unless nums.length < 2
72 | return nums if only_compress
73 |
74 | nums.empty? ? 0 : nums[0]
75 | end
76 |
77 | # 15 75 => 1,575
78 | def pair_parsing(nums, only_compress)
79 | return if (SCALES_N & nums).any?
80 |
81 | pair_parse(nums, only_compress)
82 | end
83 |
84 | def parse_each(nums)
85 | status = ParseStatus.new
86 |
87 | nums.each do |num|
88 | ParseIndividualNumber.new(status, num).call
89 | end
90 |
91 | status.calculate
92 | end
93 |
94 | def pair_parse(nums, only_compress)
95 | PairParsing.new(nums, only_compress).pair_parse
96 | end
97 | end
98 | end
99 |
--------------------------------------------------------------------------------
/_data/debt.csv:
--------------------------------------------------------------------------------
1 | DebtChange,Date,Reason,ReasonMarkdown,Active
2 | 2500000000,"Nov. 8th, 2020",Missed Noita Shot.,Missed [Noita Shot.](https://www.twitch.tv/jerma985/clip/AdventurousMiniatureMageKevinTurtle),TRUE
3 | -375,"Nov. 8th, 2020",Community Subs,[Community Subs](https://youtu.be/YixWlAtvNhk?t=16440) (75),TRUE
4 | -272310,"Nov. 9th, 2020",Lego studs,"[Lego studs](https://youtu.be/USwGGyfczR8) (1 USD = 1 LS) 272,310 Lego Studs.",TRUE
5 | -100000000,"Nov. 21st, 2020",Showed Otto :),[Showed Otto](https://youtu.be/ZNqtvglRdcE?t=20014) :),TRUE
6 | -100,"Nov. 21st, 2020",Apology,"An [apology](https://youtu.be/MhycXVLPn7I?t=463) for calling Jerma a ""boring man"".",TRUE
7 | 250000000,"Nov. 25th, 2020",GAS bet,"Jerma bets 250 million that he [hasn't said ""GAS"" more than SAW's script.](https://youtu.be/BQaSlD_UFRU?t=7300)",TRUE
8 | 2649727215,"Nov. 25th, 2020",Deal or No Deal double,The worst [Deal or No Deal play of all time.](https://youtu.be/BQaSlD_UFRU?t=10675) Debt doubled.,TRUE
9 | -153000,"Nov. 27th, 2020",Pizza Sales,All the [Pizza sales.](https://youtu.be/QIuS5aLu1_M?t=19368),TRUE
10 | -30716,"Dec. 1st, 2020",Yakuza 0 ,"For [¥3,204,259 Yen in Yakuza 0](https://youtu.be/hy6DDkbKDFg?t=21185) (1 USD = 104.32 JPY, [exchange rate](https://www.exchange-rates.org/Rate/USD/JPY/12-1-2020)) on Dec. 1st 2020.",TRUE
11 | -250000000,"Dec. 3rd, 2020",Green eggs and Ham,For a flawless reading of [green eggs and ham.](https://youtu.be/a9uuyksatqE?t=9996),TRUE
12 | 1000000000,"Dec. 9th, 2020",Impossible Quiz,Jerma bets $1 billion that he will [finish The Impossible Quiz.](https://youtu.be/5RL0ZY2xpZs?t=6431) Added in error. Thanks for [auditing!](https://www.reddit.com/r/jerma985/comments/kfw0gd/audit_the_debt/) ;),FALSE
13 | 50000000000,"Dec. 14th, 2020",Bad self dare,[Bad self dare and bad hitbox.](https://clips.twitch.tv/SweetSecretiveLardPermaSmug) Reversed: Polls decided ([[1]](https://www.strawpoll.me/42283739/r) [[2]](https://www.strawpoll.me/42283673/r) [[3]](https://www.strawpoll.me/42283794/r)).,FALSE
14 | -1000000000,"Jan. 1st, 2021",Catboy Jerma,"Beating Catboy Jerma in the [2020 Jerma Rumble.](https://clips.twitch.tv/AmorphousHelpfulHyenaSeemsGood) There was a [double or nothing](https://www.strawpoll.me/42372421), Jerma now has to [dress up as Catboy Jerma](https://clips.twitch.tv/FantasticRenownedWaffleBuddhaBar) for two streams.",FALSE
15 | -500000000,"Jan. 4th, 2021",Simpsons impressions,Doing [Simpsons impressions.](https://youtu.be/_r4U50QYbxk?t=9730) [Good points are made.](https://www.reddit.com/r/jerma985/comments/kspvwa/discussion_of_the_contested_jerma_debt_removal/),TRUE
16 | -450000000,"Jan. 4th, 2021",JermaCraft CopyPasta,JermaCraft CopyPasta as the [Family Guy Characters.](https://youtu.be/_r4U50QYbxk?t=10052) (-$50m for bad impression).,TRUE
17 | -100000000,"Jan. 6th, 2021",Jerma tells his daily routine,Jerma tells his [daily routine.](https://youtu.be/s_PHGbYxQQo?t=16214),TRUE
18 | -250000000,"Jan. 24th, 2021",Bob Ross painting ,[Follow along](https://youtu.be/f6MeRTOEbFI?t=7693) with a Bob Ross painting video,TRUE
19 | 700000,"Jan. 26th, 2021",Be a good hitman,"50K for every minute he attempted the ""[Be a good hitman](https://youtu.be/azDfFoaFo-c?t=578)"" deal. (14 Minutes)",TRUE
20 | -1500000000,"Feb. 12th, 2021",20 minutes of only funny voices,Succeeded* at doing [20 minutes of only funny voices](https://youtu.be/xUhHk4h9ivc?t=8468). *kinda had a slip but had a compromise with chat,TRUE
21 | -500000000,"Apr. 18th, 2021",Seduced Princess Peach,"Made a deal to get with Lois, ended up scoring a victory royale with princess peach. Removal confirmed via [poll](https://strawpoll.com/ggowok79z)",TRUE
22 | 10000000000,"Apr. 24th, 2021",Cartoon Baseball,Jerma is mad Part ???: [Cartoon Baseball](https://youtu.be/VBiOK8dB9Og?t=21081) (Screamed this out in rage after losing two double or nothings and somehow pulled through),FALSE
23 | -27686449,"May. 8th, 2021",Insider Trading,What's a few crimes [in and out of the stock market](https://youtu.be/qg7JTQ0S5eU)?,TRUE
24 | -250000000,"Oct. 29th, 2021",MONKE,Went bananas for [monkey videos.](https://www.youtube.com/watch?v=RyBIsz5bfUw),TRUE
25 | -10000000,"Jan. 8th, 2022",Olive Man,[Edward Olivehands.](https://www.youtube.com/watch?v=pvjStBPiUH4),TRUE
26 | 1,"May. 2nd, 2022",Stanley Parable Achievement,[Bet $1](https://www.youtube.com/watch?v=Cbm3_HmU2NQ) that the narrator wouldn't let him get an achievement and then the narrator let him get the achievement.,FALSE
27 | 40000000,"May. 3rd, 2022",Infomercial Giveaway,Promised chat [$40 million](https://www.youtube.com/watch?v=AY6SdTHcLfk) via an infomercial giveaway which proceeded to never deliver.,TRUE
28 |
--------------------------------------------------------------------------------
/scripts.js:
--------------------------------------------------------------------------------
1 | async function getChart(results) {
2 | let labels = [], allPaid = [], colors = [];
3 | let time = [], event = [], additiveDebt = [], eventReason = [];
4 | var count = 0;
5 | var ctxLine = document.getElementById('lineChart').getContext('2d');
6 |
7 | var dynamicColors = function(test) {
8 | var r = 0;
9 | var g = 0 + test;
10 | var b = 245;
11 | return "rgb(" + r + "," + g + "," + b + ")";
12 | };
13 |
14 | var totalEvents = 0;
15 | //how much should we change each colour by?
16 | for(var item of results) {
17 | if(item.Active == "TRUE") {
18 | if(item.DebtChange < 0) {
19 | totalEvents++;
20 | }
21 | }
22 | }
23 |
24 | // Color of paid debts
25 | for(var item of results) {
26 | if(item.Active == "TRUE") {
27 | var paidDebt = Number(item.DebtChange);
28 | event.push(paidDebt);
29 | eventReason.push(item.Reason);
30 | event.reduce(function(a,b,i) { return additiveDebt[i] = a+b; }, 0);
31 | time.push(item.Date);
32 | if(item.DebtChange < 0) {
33 | allPaid.push(paidDebt);
34 | labels.push(item.Reason);
35 | colors.push(dynamicColors(count));
36 | count += Math.round(((100 / totalEvents) * 2)); //change extremes between colors
37 | }
38 | }
39 | }
40 |
41 | allPaid.push(additiveDebt[additiveDebt.length - 1]);
42 | labels.push("Debt Left");
43 |
44 | additiveDebt.push(additiveDebt[additiveDebt.length - 1]);
45 | event.push(0);
46 | eventReason.push("Current Day");
47 | time.push(new Date());
48 |
49 | new Chart(ctxLine, {
50 | type: 'line',
51 | data: {
52 | labels: time,
53 | datasets: [{
54 | data: additiveDebt,
55 | pointBorderColor: '#c2394a',
56 | pointBackgroundColor: '#c2394a',
57 | borderColor: 'rgb(75, 192, 192)',
58 | backgroundColor: 'rgba(28,59,80,0.5)',
59 | fill: true,
60 | tension: 0
61 | }]
62 | },
63 |
64 | options: {
65 | legend: { display: false },
66 | responsive: true,
67 | onResize: function(chart, size) {
68 | chart.update();
69 | chart.padding = {
70 | // top: 5 * (parseInt(getComputedStyle(document.getElementById("lineChart")).fontSize)),
71 | // bottom: 3 * (parseInt(getComputedStyle(document.getElementById("lineChart")).fontSize)),
72 | left: (parseInt(getComputedStyle(document.getElementById("div-wrapper")).paddingRight)),
73 | right: (parseInt(getComputedStyle(document.getElementById("div-wrapper")).paddingRight)),
74 | }
75 | },
76 | layout: {
77 | padding: {
78 | // top: 5 * (parseInt(getComputedStyle(document.getElementById("lineChart")).fontSize)),
79 | // bottom: 3 * (parseInt(getComputedStyle(document.getElementById("lineChart")).fontSize)),
80 | left: (parseInt(getComputedStyle(document.getElementById("div-wrapper")).paddingRight)),
81 | right: (parseInt(getComputedStyle(document.getElementById("div-wrapper")).paddingRight)),
82 | }
83 | },
84 | scales: {
85 | xAxes: [{
86 | type: 'time',
87 | time: {
88 | parser: "MMM. Do, YYYY",
89 | },
90 | ticks: {
91 | fontSize: 18,
92 | maxTicksLimit: 20
93 | },
94 | gridLines: {
95 | color: ""
96 | }
97 | }],
98 | yAxes: [{
99 | ticks: {
100 | fontSize: 18,
101 | callback: function(value, index, values) {
102 | return ('$' + value.toLocaleString()).replace("$-", "-$");
103 | }
104 | },
105 | gridLines: {
106 | color: "#FFFFFF"
107 | }
108 | }]
109 | },
110 | tooltips: {
111 | enabled: true,
112 | mode: 'single',
113 | callbacks: {
114 | title: function(tooltipItems, data) {
115 | return data.labels[tooltipItems[0].index]
116 | // return new Intl.DateTimeFormat('en-US', { dateStyle: 'full', timeStyle: 'long' }).format(data.labels[tooltipItems[0].index]);
117 | },
118 | label: function(tooltipItem) {
119 | return ('$' + additiveDebt[tooltipItem.index].toLocaleString()).replace("$-", "-$");
120 | },
121 | beforeFooter: function(tooltipItems, data) {
122 | return ("+$" + event[tooltipItems[0].index].toLocaleString()).replace("+$-", "-$");
123 | },
124 | footer: function(tooltipItems, data) {
125 | return eventReason[tooltipItems[0].index];
126 | }
127 | }
128 | }
129 | },
130 | });
131 | }
132 |
133 | function randomInRange(min, max) {
134 | return Math.random() * (max - min) + min;
135 | }
136 |
137 | (async () => {
138 | Chart.defaults.global.defaultFontFamily = "Ubuntu";
139 | Chart.defaults.global.defaultFontColor = "white";
140 | Chart.defaults.global.fontSize = 18;
141 | d3.csv("_data/debt.csv").then(getChart);
142 |
143 | var debt = parseInt((document.getElementById("debtCounterNum").innerHTML.slice(1)).replace(/,/g, ''));
144 |
145 | if (debt == 0) {
146 | var duration = 15000;
147 | var animationEnd = Date.now() + duration;
148 | var colors = ["#a64ca6", "#4ca6a6"];
149 | var defaults = {startVelocity: 30, spread: 360, ticks: 60, zIndex: 0, scalar: 1.5, colors: colors,};
150 |
151 | (function frame() {
152 |
153 | var timeLeft = animationEnd - Date.now();
154 |
155 | var particleCount = 4 * (timeLeft / duration);
156 |
157 | // since particles fall down, start a bit higher than random
158 | confetti(Object.assign({}, defaults, {particleCount, origin: {x: randomInRange(0.3, 0.5), y: Math.random() +.1 }}));
159 | confetti(Object.assign({}, defaults, {particleCount, origin: {x: randomInRange(0.5, 0.7), y: Math.random() +.1 }}));
160 |
161 | //side confetti
162 |
163 | confetti({
164 | particleCount: 2,
165 | angle: 50,
166 | spread: 55,
167 | origin: {x: 0},
168 | scalar: 1.5,
169 | ticks: 400,
170 | colors: colors,
171 | });
172 | confetti({
173 | particleCount: 2,
174 | angle: 130,
175 | spread: 55,
176 | origin: {x: 1},
177 | scalar: 1.5,
178 | ticks: 400,
179 | colors: colors,
180 | });
181 |
182 | if (Date.now() < animationEnd) {
183 | requestAnimationFrame(frame);
184 | }
185 | })();
186 | }
187 | })();
188 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 |
5 |
6 |
7 |
8 | Jerma Debt Tracker
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
25 |
26 | {% assign debtTotal = 0 %}
27 | {% for event in site.data.debt %}
28 | {%- if event.Active != "FALSE" -%}
29 | {% assign debtTotal = debtTotal | plus: event.DebtChange %}
30 | {%- endif -%}
31 | {% endfor %}
32 |
${{debtTotal | intcomma }}
33 |
34 | {% assign numwords = debtTotal | num2words %}
35 | {{ numwords | slice: 1, numwords.size | capitalize_all | replace: "And", "and"}}
36 |
37 |
38 |
39 |
40 | On the 8th of November 2020, at approximately 6pm, popular e-clown Jerma985 bet his chat, while playing the game Noita, that if he missed the next shot on the the next enemy, he would owe chat 500 million community subs.
41 | Jerma985 then proceeded miss the next shot he took. This brings his debt to chat to an original two and a half billion US dollars.
42 | This website will track as Jerma slowly whittles away (or adds to) his debt to chat
43 | This guy is fucked .
44 |
45 |
46 |
47 |
Debt Tracker
48 |
49 |
55 |
56 | {% assign debtTotal = 0 %}
57 | {% for event in site.data.debt %}
58 |
59 |
60 |
{{ event.Date }}
61 | {% assign classes = 'debtChange ' %}
62 |
63 | {%- if event.Active == "FALSE" -%}
64 | {% assign classes = classes | append: 'debtInvalid ' %}
65 | {%- else -%}
66 | {% assign debtTotal = debtTotal | plus: event.DebtChange %}
67 | {%- endif -%}
68 |
69 | {%- if event.DebtChange contains "-" -%}
70 | {% assign classes = classes | append: 'debtRemove' %}
71 | {%- else -%}
72 | {% assign classes = classes | append: 'debtAdd' %}
73 | {%- endif -%}
74 |
75 |
76 | {%- if event.DebtChange contains "-" -%}
77 | -${{ event.DebtChange | slice: 1,event.DebtChange.size | intcomma }}
78 | {%- else -%}
79 | +${{ event.DebtChange | intcomma }}
80 | {%- endif -%}
81 |
82 |
{{ event.ReasonMarkdown | markdownify | remove: ' ' | remove: '
' }}
83 |
${{debtTotal | intcomma }}
84 |
85 | {% endfor %}
86 |
87 |
88 |
89 |
90 |
94 |
95 |
96 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/assets/css/styles.scss:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | $purple-one: #190019;
5 | $purple-two: #110011;
6 |
7 | /* ubuntu-regular - latin */
8 | @font-face {
9 | font-family: 'Ubuntu';
10 | font-style: normal;
11 | font-weight: 400;
12 | src:
13 | url('../fonts/ubuntu-v15-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
14 | url('../fonts/ubuntu-v15-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
15 | }
16 |
17 | /* ubuntu-700 - latin */
18 | @font-face {
19 | font-family: 'Ubuntu';
20 | font-style: normal;
21 | font-weight: 700;
22 | src:
23 | url('../fonts/ubuntu-v15-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
24 | url('../fonts/ubuntu-v15-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
25 | }
26 |
27 |
28 | html, body {
29 | max-width: 100%;
30 | overflow-x: hidden;
31 | }
32 |
33 | body {
34 | margin: 0;
35 | }
36 |
37 | /* Header Bar and Text */
38 | header {
39 | text-align: center;
40 | padding: 5px;
41 | font-weight: normal;
42 | background-color: #69bbc3;
43 | color: white;
44 | font-family: 'Ubuntu',sans-serif;
45 | height: 11vh;
46 | font-size: 3vh;
47 | display: flex;
48 | justify-content: center;
49 | align-items: center;
50 | }
51 |
52 | .data-display {
53 | height: 89vh;
54 | background-image:url("../images/jermass.png");
55 | background-size: cover;
56 | background-attachment: fixed;
57 | background-position-x: center;
58 | background-position-y: center;
59 | display: flex;
60 | justify-content: center;
61 | align-items: center;
62 | flex-direction: column;
63 | color: #ffffff;
64 | font-family: 'Ubuntu',sans-serif;
65 | h1 {
66 | margin: 10px;
67 | font-size: 12.5vw;
68 | font-weight: 700;
69 | }
70 | /* Amount in Words */
71 | h2 {
72 | text-align: center;
73 | line-height: 200%;
74 | margin: 5px;
75 | font-size: 150%;
76 | }
77 | }
78 |
79 | /* History of the debt text */
80 | article {
81 | font-family: 'Ubuntu',sans-serif;
82 | font-size: 150%;
83 | line-height: 200%;
84 | text-align: center;
85 | background-color: #404040;
86 | color: white;
87 | .intro {
88 | padding-top: 50px;
89 | padding-bottom: 50px;
90 | padding-left: 10%;
91 | padding-right: 10%;
92 | text-align: center;
93 | color: #fff;
94 | p {
95 | font-size: 20px;
96 | }
97 | }
98 | /* Poll Zone */
99 | .notice {
100 | font-family: ubuntu,sans-serif;
101 | font-size: 100%;
102 | padding: 15px;
103 | text-align: center;
104 | background-color: #2c2c2c;
105 | color: #fff;
106 | word-wrap: normal;
107 | h1 {
108 | text-decoration-style: dotted;
109 | a:link {
110 | color: #fff;
111 | background-color: transparent;
112 | text-decoration-style: dotted;
113 | }
114 | a:visited {
115 | color: #fff;
116 | }
117 | a:hover {
118 | color: #d3d3d3;
119 | background-color: transparent;
120 | text-decoration-style: solid;
121 | }
122 | }
123 | }
124 | }
125 |
126 | .head-link{
127 | color: white;
128 | background-color: transparent;
129 | text-decoration: none;
130 | &:visited,&:active,&:hover,&:focus {
131 | color: white;
132 | background-color: transparent;
133 | text-decoration: none;
134 | }
135 | }
136 |
137 | .debt {
138 | font-size: 16px;
139 | background-color: $purple-one;
140 | a:link {
141 | color: #45c1ff;
142 | background-color: transparent;
143 | text-decoration: none;
144 | }
145 | a:visited {
146 | color: #82A3DD;
147 | background-color: transparent;
148 | text-decoration: none;
149 | }
150 | a:hover {
151 | color: #FFFFFF;
152 | background-color: transparent;
153 | text-decoration: underline;
154 | }
155 | a:active {
156 | color: #ff4545;
157 | background-color: transparent;
158 | text-decoration: underline;
159 | }
160 | h1 {
161 | padding-left: 8px;
162 | font-size: 30px;
163 | margin-top: 0px;
164 | padding-top: 30px;
165 | margin-bottom: 0px;
166 | padding-bottom: 20px;
167 | text-align: left;
168 | }
169 | }
170 |
171 | #div-wrapper {
172 | width: 80%;
173 | padding-left: 10%;
174 | padding-right: 10%;
175 | }
176 |
177 | .headerRow {
178 | width: 100%;
179 | float: left;
180 | border-top: thin solid #3D3D3D;
181 | background-color: #2f192f;
182 | }
183 | .runningTotal {
184 | margin: 0px;
185 | padding: 8px;
186 | width: 124px;
187 | float: left;
188 | text-align: right;
189 | font-weight: normal;
190 | }
191 | .row {
192 | width: 100%;
193 | float: left;
194 | border-bottom: thin solid #3D3D3D;
195 | }
196 | .row-alt {
197 | width: 100%;
198 | float: left;
199 | border-bottom: thin solid #3D3D3D;
200 | background-color: #2f192f;
201 | }
202 | .date {
203 | padding: 8px;
204 | margin: 0px;
205 | width: 110px;
206 | float: left;
207 | text-align: left;
208 | font-weight: normal;
209 | white-space: nowrap;
210 | }
211 | .debtChange {
212 | padding: 8px;
213 | margin: 0px;
214 | width: 159px;
215 | float: left;
216 | text-align: center;
217 | font-weight: normal;
218 | }
219 |
220 | .debtAdd {
221 | color: #c53929;
222 | }
223 |
224 | .debtRemove {
225 | color: #0b8043;
226 | }
227 |
228 | .debtInvalid {
229 | color: #f09300 !important;
230 | text-decoration: line-through !important;
231 | }
232 |
233 | .reason {
234 | width: calc(100% - 457px);
235 | float: left;
236 | padding: 8px;
237 | margin: 0px;
238 | text-align: left;
239 | font-weight: normal;
240 | }
241 | .web {
242 | width: 86%;
243 | padding-top: 30px;
244 | padding-bottom: 20px;
245 | padding-left: 7%;
246 | padding-right: 7%;
247 | }
248 |
249 | .mobile {
250 | display: none;
251 | }
252 | footer {
253 | padding-top: 15px;
254 | padding-bottom: 15px;
255 | text-decoration-style: dotted;
256 | a:link {
257 | color: #fff;
258 | background-color: transparent;
259 | text-decoration-style: dotted;
260 | }
261 | a:visited {
262 | color: #fff;
263 | }
264 | a:hover {
265 | color: #d3d3d3;
266 | background-color: transparent;
267 | text-decoration-style: solid;
268 | }
269 |
270 | span {
271 | display: inline-block;
272 | }
273 | }
274 |
275 |
276 | @media screen and (max-width: 1250px) {
277 | .web{
278 | width: 100%;
279 | padding-left: 0%;
280 | padding-right: 0%;
281 | padding-top: 30px;
282 | padding-bottom: 20px;
283 | }
284 | #div-wrapper {
285 | width: 90%;
286 | padding-left: 5%;
287 | padding-right: 5%;
288 | line-height: 150%;
289 | }
290 | }
291 |
292 | @media screen and (max-width: 780px) {
293 | #div-wrapper {
294 | width: 90%;
295 | padding-left: 5%;
296 | padding-right: 5%;
297 | line-height: 125%;
298 | }
299 | .reason {
300 | width: calc(100% - 156px);
301 | }
302 | .date{
303 | width: calc(50% - 16px);
304 | padding: 8px 8px 0px 8px;
305 | font-weight: bold;
306 | }
307 | .debtChange{
308 | width: calc(50% - 16px);
309 | text-align: right;
310 | padding: 8px 8px 0px 8px;
311 | font-weight: bold;
312 | }
313 | .headerRow{
314 | display: none;
315 | }
316 | .web{
317 | display: none;
318 | }
319 | .mobile{
320 | display: initial;
321 | width: 100%;
322 | padding-top: 30px;
323 | padding-bottom: 20px;
324 | }
325 | }
326 |
327 | /* Visualized Title */
328 |
329 | .visualized {
330 | text-align: left;
331 | background-color: #550968;
332 | padding-bottom: 30px;
333 | padding-top: 20px;
334 | padding-left: 10%;
335 | padding-right: 10%;
336 | height: 75vh !important;
337 | .lh {
338 | text-align: left;
339 | text-align: center;
340 | font-size: 105%;
341 | width: 100vw;
342 | background-color: #530866;
343 | margin-left: -10.5vw;
344 | margin-top: -20px;
345 | margin-bottom: 5px;
346 | }
347 | }
348 |
349 | #lineChart {
350 | padding-top: 5rem;
351 | padding-bottom: 3rem;
352 | // padding-left: 10%;
353 | // padding-right: 10%;
354 | background-color: $purple-two;
355 | }
356 |
--------------------------------------------------------------------------------
/_plugins/humanize.rb:
--------------------------------------------------------------------------------
1 | module Jekyll
2 |
3 | module Humanize
4 | ##
5 | # This is a port of the Django app `humanize` which adds a "human touch"
6 | # to data. Given that Jekyll produces static sites, some of the original
7 | # methods do not make logical sense (e.g. naturaltime).
8 | #
9 | # Source code can be viewed here:
10 | # https://github.com/django/django
11 | #
12 | # Copyright (c) Django Software Foundation and individual contributors.
13 | # All rights reserved.
14 |
15 | ####################
16 | # PUBLIC METHODS #
17 | ####################
18 |
19 | def ordinal(value, flag=nil)
20 | ##
21 | # Converts an integer to its ordinal as a string. 1 is '1st', 2 is '2nd',
22 | # 3 is '3rd', etc. Works for any integer.
23 | #
24 | # Usage:
25 | # {{ somenum }} >>> 3
26 | # {{ somenum | ordinal }} >>> '3rd'
27 | # {{ somenum | ordinal: "super" }} >>> '3rd '
28 |
29 | begin
30 | value = value.to_i
31 | flag.to_s.downcase!
32 | rescue Exception => e
33 | puts "#{e.class} #{e}"
34 | return value
35 | end
36 |
37 | suffix = ""
38 | suffixes = ["th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"]
39 | unless [11, 12, 13].include? value % 100 then
40 | suffix = suffixes[value % 10]
41 | else
42 | suffix = suffixes[0]
43 | end
44 |
45 | unless flag and flag == "super"
46 | return "#{value}%s" % suffix
47 | else
48 | return "#{value}%s " % suffix
49 | end
50 |
51 | end
52 |
53 | def intcomma(value, delimiter=",")
54 | ##
55 | # Converts an integer to a string containing commas every three digits.
56 | # For example, 3000 becomes '3,000' and 45000 becomes '45,000'.
57 | # Optionally supports a delimiter override for commas.
58 | #
59 | # Usage:
60 | # {{ post.content | number_of_words }} >>> 12345
61 | # {{ post.content | number_of_words | intcomma }} >>> '12,345'
62 | # {{ post.content | number_of_words | intcomma: '.' }} >>> '12.345'
63 |
64 | begin
65 | orig = value.to_s
66 | delimiter = delimiter.to_s
67 | rescue Exception => e
68 | puts "#{e.class} #{e}"
69 | return value
70 | end
71 |
72 | copy = orig.strip
73 | copy = orig.gsub(/^(-?\d+)(\d{3})/, "\\1#{delimiter}\\2")
74 | orig == copy ? copy : intcomma(copy, delimiter)
75 | end
76 |
77 | INTWORD_HELPERS = [
78 | [6, "million"],
79 | [9, "billion"],
80 | [12, "trillion"],
81 | [15, "quadrillion"],
82 | [18, "quintillion"],
83 | [21, "sextillion"],
84 | [24, "septillion"],
85 | [27, "octillion"],
86 | [30, "nonillion"],
87 | [33, "decillion"],
88 | [100, "googol"],
89 | ]
90 |
91 | def intword(value)
92 | ##
93 | # Converts a large integer to a friendly text representation. Works best
94 | # for numbers over 1 million. For example, 1000000 becomes '1.0 million',
95 | # 1200000 becomes '1.2 million' and 1200000000 becomes '1.2 billion'.
96 | #
97 | # Usage:
98 | # {{ largenum }} >>> 1200000
99 | # {{ largenum | intword }} >>> '1.2 million'
100 |
101 | begin
102 | value = value.to_i
103 | rescue Exception => e
104 | puts "#{e.class} #{e}"
105 | return value
106 | end
107 |
108 | if value < 1000000
109 | return value
110 | end
111 |
112 | for exponent, text in INTWORD_HELPERS
113 | large_number = 10 ** exponent
114 |
115 | if value < large_number * 1000
116 | return "%#{value}.1f #{text}" % (value / large_number.to_f)
117 | end
118 |
119 | end
120 |
121 | return value
122 | end
123 |
124 | def apnumber(value)
125 | ##
126 | # For numbers 0-9, returns the number spelled out. Otherwise, returns the
127 | # number. This follows Associated Press style.
128 | #
129 | # Usage:
130 | # {{ num }} >>> 6
131 | # {{ num | apnumber }} >>> six
132 |
133 | begin
134 | value = value.to_i
135 | rescue Exception => e
136 | puts "#{e.class} #{e}"
137 | return value
138 | end
139 |
140 | unless value >= 0 and value < 10 then
141 | return value
142 | else
143 | return ["zero", "one", "two", "three", "four", "five", "six",
144 | "seven", "eight", "nine"][value]
145 | end
146 |
147 | end
148 |
149 | def naturalday(date)
150 | ##
151 | # For date values that are within a 9 day stretch from present day, this
152 | # will attempt to return the string representation in the format of today,
153 | # tomorrow, yesterday, "in # days" or "# days ago". Otherwise, returns a
154 | # string formatted according to the "date_format" setting in your
155 | # _config.yml file using strftime format (if not defined, it will default
156 | # to "%m/%d/%Y").
157 | #
158 | # Usage:
159 | # TODAY == 01/26/2014
160 | # {{ post.updated }} >>> 01/25/2014
161 | # {{ post.updated | naturalday }} >>> 'yesterday'
162 | # {{ post.date }} >>> 01/19/2014
163 | # {{ post.date | naturalday }} >>> 'seven days ago'
164 |
165 | begin
166 | site = @context.registers[:site]
167 | date_format = site.config['humanize']['date_format']
168 | date = time(date).to_date
169 | rescue Exception => e
170 | puts "#{e.class} #{e}"
171 | return date
172 | end
173 |
174 | unless date_format then
175 | date_format = "%m/%d/%Y"
176 | end
177 |
178 | today = time(Time.now).to_date
179 | delta = (date - today).to_i
180 |
181 | case delta
182 | when 0
183 | return "today"
184 | when 1
185 | return "tomorrow"
186 | when 2..9
187 | delta = apnumber(delta)
188 | return "in #{delta} days"
189 | when -1
190 | return "yesterday"
191 | when -9..-2
192 | delta = apnumber(delta * -1)
193 | return "#{delta} days ago"
194 | else
195 | return date.strftime("#{date_format}")
196 | end
197 |
198 | end
199 |
200 | def filesize(value)
201 | ##
202 | # For filesize values in bytes, returns the number rounded to 3
203 | # decimal places with the correct suffix.
204 | #
205 | # Usage:
206 | # {{ bytes }} >>> 123456789
207 | # {{ bytes | filesize }} >>> 117.738 MB
208 | filesize_tb = 1099511627776.0
209 | filesize_gb = 1073741824.0
210 | filesize_mb = 1048576.0
211 | filesize_kb = 1024.0
212 |
213 | begin
214 | value = value.to_f
215 | rescue Exception => e
216 | puts "#{e.class} #{e}"
217 | return value
218 | end
219 |
220 | if value >= filesize_tb
221 | return "%s TB" % (value / filesize_tb).to_f.round(3)
222 | elsif value >= filesize_gb
223 | return "%s GB" % (value / filesize_gb).to_f.round(3)
224 | elsif value >= filesize_mb
225 | return "%s MB" % (value / filesize_mb).to_f.round(3)
226 | elsif value >= filesize_kb
227 | return "%s KB" % (value / filesize_kb).to_f.round(0)
228 | elsif value == 1
229 | return "1 byte"
230 | else
231 | return "%s bytes" % value.to_f.round(0)
232 | end
233 |
234 | end
235 |
236 | #####################
237 | # PRIVATE METHODS #
238 | #####################
239 |
240 | private
241 | def time(input)
242 | case input
243 | when Time
244 | input
245 | when String
246 | Time.parse(input)
247 | else
248 | Jekyll.logger.error "Invalid Date:", "'#{input}' not valid datetime."
249 | exit(1)
250 | end
251 | end
252 |
253 | end
254 |
255 | end
256 |
257 | Liquid::Template.register_filter(Jekyll::Humanize)
258 |
--------------------------------------------------------------------------------
/_includes/bundle.js:
--------------------------------------------------------------------------------
1 | (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;it.length)&&(e=t.length);for(var r=0,n=new Array(e);rn?r:n).toString().length)),this.setSelect(this.from),void 0!==u&&(l?setTimeout((function(){return i.flipTo({to:i.to})}),1e3*l):this.flipTo({to:this.to}))}var e,r,o;return e=t,(r=[{key:"_initHTML",value:function(t){var e,r=this;this.node.classList.add("number-flip"),this.node.style.position="relative",this.node.style.overflow="hidden";for(var o=0;o=0;r-=1){var n=this.afterArr[r]-this.beforeArr[r];e+=n,this._draw({digit:r,per:this.easeFn(t),alter:this.direct?n:e}),e*=10}}},{key:"flipTo",value:function(t){var e=this,r=t.to,n=t.duration,i=t.easeFn,o=t.direct;i&&(this.easeFn=i),void 0!==o&&(this.direct=o),this.setSelect(r);var a=this.ctnrArr.length;this.beforeArr=s(this.from,a),this.afterArr=s(r,a);var u=Date.now(),c=1e3*n||this.duration;requestAnimationFrame((function t(){var n=Date.now()-u;e.frame(n/c),n