Merge branch 'master' into fix/table-not-rendered-correctly

master
rex.tsou 5 years ago committed by GitHub
commit 55635e73f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,2 +1,3 @@
github: github:
- mikebryant - mikebryant
- theRTC204

@ -0,0 +1,49 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Things to check**
- Have you forced a refresh in your browser (e.g. ctrl+F5 in Chrome/Firefox)?
- yes/no
- Have you made sure the first time buyer option is correct? If you're unsure, try it both ways
- yes/no
- Have you time-travelled this week? Travelling backwards resets the prices, and therefore you must not put prices in from both before & after the time-travel
- yes/no
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Permalink to your prices**
Please click the `Copy Permalink` button and paste it here
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

@ -0,0 +1,10 @@
# Configuration for probot-no-response - https://github.com/probot/no-response
daysUntilClose: 7
responseRequiredLabel: more information required
closeComment: >
This issue has been automatically closed because there has been no response
to our request for more information from the original author. With only the
information that is currently in the issue, we don't have enough information
to take action. Please reach out if you have or find the answers we need so
that we can investigate further.

@ -304,7 +304,7 @@ input[type=number] {
padding: 8px 16px; padding: 8px 16px;
border-width: 0px; border-width: 0px;
border-radius: 40px; border-radius: 40px;
background: transparent; background: #F3F3F3;
font-size: 1.2rem; font-size: 1.2rem;
transition: 0.2s all; transition: 0.2s all;
position: relative; position: relative;
@ -329,6 +329,7 @@ input[type=number] {
margin: 0px auto; margin: 0px auto;
box-sizing: border-box; box-sizing: border-box;
overflow-x: auto; overflow-x: auto;
scrollbar-width: thin;
} }
@media only screen and (max-width: 1440px) and (pointer: fine) { @media only screen and (max-width: 1440px) and (pointer: fine) {
@ -557,17 +558,8 @@ input[type=number] {
z-index: 1; z-index: 1;
} }
.darkmode-toggle {
opacity: 0.7;
transition: opacity 0.15s;
}
.darkmode-toggle:hover { .darkmode-toggle:hover {
opacity: 0.9; filter: brightness(0.9);
}
.darkmode-toggle:active {
transition: opacity 0s;
opacity: 1;
} }
.darkmode-toggle:focus { .darkmode-toggle:focus {
@ -590,36 +582,35 @@ body.darkmode--activated{
font-family: 'Varela Round', sans-serif; font-family: 'Varela Round', sans-serif;
width: 100%; width: 100%;
margin: 0 0 0 0; margin: 0 0 0 0;
position: absolute position: absolute;
} }
body.darkmode--activated div[class^="dialog-box"], body.darkmode--activated div[class^="dialog-box"],
body.darkmode--activated div[class^="nook-phone"], body.darkmode--activated div[class^="nook-phone"],
body.darkmode--activated form[class^="input__form"], body.darkmode--activated form[class^="input__form"] {
{
background: #fee0c4; background: #fee0c4;
color: #010F1D; color: #010F1D;
} }
body.darkmode--activated svg[class^="waves"]{ body.darkmode--activated svg[class^="waves"] {
background: #fef0e3; background: #fef0e3;
} }
body.darkmode--activated a, body.darkmode--activated a,
body.darkmode--activated b, body.darkmode--activated b,
body.darkmode--activated input[type=number]:not(:placeholder-shown){ body.darkmode--activated input[type=number]:not(:placeholder-shown) {
color: #586472; color: #586472;
} }
body.darkmode--activated input[type="radio"]+label, body.darkmode--activated input[type="radio"]+label,
body.darkmode--activated input[type=number]:placeholder-shown{ body.darkmode--activated input[type=number]:placeholder-shown {
background: #bda284; background: #bda284;
} }
body.darkmode--activated input[type="radio"]:checked+label{ body.darkmode--activated input[type="radio"]:checked+label {
background: #7b6955; background: #7b6955;
} }
body.darkmode--activated i{ body.darkmode--activated i {
color: #7b6955; color: #7b6955;
} }

@ -110,7 +110,7 @@
<h6 data-i18n="weekdays.sunday"></h6> <h6 data-i18n="weekdays.sunday"></h6>
<div class="input__group"> <div class="input__group">
<label data-i18n="[html]prices.description"></label> <label data-i18n="[html]prices.description"></label>
<input type="number" id="buy" placeholder="..." /> <input type="number" pattern="\d*" id="buy" placeholder="..." />
</div> </div>
</div> </div>
@ -121,11 +121,11 @@
<h6 data-i18n="weekdays.monday"></h6> <h6 data-i18n="weekdays.monday"></h6>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.morning" for="sell_2"></label> <label data-i18n="times.morning" for="sell_2"></label>
<input type="number" id="sell_2" placeholder="..." /> <input type="number" pattern="\d*" id="sell_2" placeholder="..." />
</div> </div>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.afternoon" for="sell_3"></label> <label data-i18n="times.afternoon" for="sell_3"></label>
<input type="number" id="sell_3" placeholder="..." /> <input type="number" pattern="\d*" id="sell_3" placeholder="..." />
</div> </div>
</div> </div>
@ -133,11 +133,11 @@
<h6 data-i18n="weekdays.tuesday"></h6> <h6 data-i18n="weekdays.tuesday"></h6>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.morning" for="sell_4"></label> <label data-i18n="times.morning" for="sell_4"></label>
<input type="number" id="sell_4" placeholder="..." /> <input type="number" pattern="\d*" id="sell_4" placeholder="..." />
</div> </div>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.afternoon" for="sell_5"></label> <label data-i18n="times.afternoon" for="sell_5"></label>
<input type="number" id="sell_5" placeholder="..." /> <input type="number" pattern="\d*" id="sell_5" placeholder="..." />
</div> </div>
</div> </div>
@ -145,11 +145,11 @@
<h6 data-i18n="weekdays.wednesday"></h6> <h6 data-i18n="weekdays.wednesday"></h6>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.morning" for="sell_6"></label> <label data-i18n="times.morning" for="sell_6"></label>
<input type="number" id="sell_6" placeholder="..." /> <input type="number" pattern="\d*" id="sell_6" placeholder="..." />
</div> </div>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.afternoon" for="sell_7"></label> <label data-i18n="times.afternoon" for="sell_7"></label>
<input type="number" id="sell_7" placeholder="..." /> <input type="number" pattern="\d*" id="sell_7" placeholder="..." />
</div> </div>
</div> </div>
@ -157,11 +157,11 @@
<h6 data-i18n="weekdays.thursday"></h6> <h6 data-i18n="weekdays.thursday"></h6>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.morning" for="sell_8"></label> <label data-i18n="times.morning" for="sell_8"></label>
<input type="number" id="sell_8" placeholder="..." /> <input type="number" pattern="\d*" id="sell_8" placeholder="..." />
</div> </div>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.afternoon" for="sell_9"></label> <label data-i18n="times.afternoon" for="sell_9"></label>
<input type="number" id="sell_9" placeholder="..." /> <input type="number" pattern="\d*" id="sell_9" placeholder="..." />
</div> </div>
</div> </div>
@ -169,11 +169,11 @@
<h6 data-i18n="weekdays.friday"></h6> <h6 data-i18n="weekdays.friday"></h6>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.morning" for="sell_10"></label> <label data-i18n="times.morning" for="sell_10"></label>
<input type="number" id="sell_10" placeholder="..." /> <input type="number" pattern="\d*" id="sell_10" placeholder="..." />
</div> </div>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.afternoon" for="sell_11"></label> <label data-i18n="times.afternoon" for="sell_11"></label>
<input type="number" id="sell_11" placeholder="..." /> <input type="number" pattern="\d*" id="sell_11" placeholder="..." />
</div> </div>
</div> </div>
@ -181,11 +181,11 @@
<h6 data-i18n="weekdays.saturday"></h6> <h6 data-i18n="weekdays.saturday"></h6>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.morning" for="sell_12"></label> <label data-i18n="times.morning" for="sell_12"></label>
<input type="number" id="sell_12" placeholder="..." /> <input type="number" pattern="\d*" id="sell_12" placeholder="..." />
</div> </div>
<div class="input__group"> <div class="input__group">
<label data-i18n="times.afternoon" for="sell_13"></label> <label data-i18n="times.afternoon" for="sell_13"></label>
<input type="number" id="sell_13" placeholder="..." /> <input type="number" pattern="\d*" id="sell_13" placeholder="..." />
</div> </div>
</div> </div>
</div> </div>
@ -213,7 +213,6 @@
<tr> <tr>
<th valign="bottom" data-i18n="patterns.pattern"></th> <th valign="bottom" data-i18n="patterns.pattern"></th>
<th colspan="2" valign="bottom" data-i18n="output.chance"></th> <th colspan="2" valign="bottom" data-i18n="output.chance"></th>
<th valign="bottom" data-i18n="weekdays.sunday"></th>
<th colspan="2"> <th colspan="2">
<div data-i18n="weekdays.monday"></div> <div data-i18n="weekdays.monday"></div>
<div> <div>
@ -229,12 +228,10 @@
</div> </div>
</th> </th>
<th colspan="2"> <th colspan="2">
<div data-i18n="weekdays.wednesday"></div>
<div> <div>
<div data-i18n="weekdays.wednesday"></div> <span data-i18n="times.morning"></span>
<div> <span data-i18n="times.afternoon"></span>
<span data-i18n="times.morning"></span>
<span data-i18n="times.afternoon"></span>
</div>
</div> </div>
</th> </th>
<th colspan="2"> <th colspan="2">
@ -297,6 +294,7 @@
<p data-i18n="[html]textbox.support"></p> <p data-i18n="[html]textbox.support"></p>
<p data-i18n="textbox.contributors-text"></p> <p data-i18n="textbox.contributors-text"></p>
<p id="contributors"><span data-i18n="textbox.contributors"></span>: </p> <p id="contributors"><span data-i18n="textbox.contributors"></span>: </p>
<p data-i18n="[html]textbox.sponsor"></p>
<div class="dialog-box-lng"> <div class="dialog-box-lng">
<p data-i18n="textbox.language"></p>: <select id="language"></select> <p data-i18n="textbox.language"></p>: <select id="language"></select>
</div> </div>
@ -314,7 +312,7 @@
<script src="js/predictions.js"></script> <script src="js/predictions.js"></script>
<script src="js/scripts.js"></script> <script src="js/scripts.js"></script>
<script src="https://cdn.jsdelivr.net/npm/darkmode-js@1.5.5/lib/darkmode-js.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/darkmode-js@1.5.5/lib/darkmode-js.min.js"></script>
<script> new Darkmode({label: '🌓', buttonColorDark: '#fff00'}).showWidget();</script> <script>new Darkmode({label: '🌓', buttonColorDark: '#dddddd'}).showWidget();</script>
<script src="js/translations.js"></script> <script src="js/translations.js"></script>
<script src="js/contributors.js"></script> <script src="js/contributors.js"></script>
<script> <script>

@ -56,10 +56,64 @@ function range_intersect_length(range1, range2) {
return range_length(range_intersect(range1, range2)); return range_length(range_intersect(range1, range2));
} }
/**
* Accurately sums a list of floating point numbers.
* See https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements
* for more information.
* @param {number[]} input
* @returns {number} The sum of the input.
*/
function float_sum(input) {
// Uses the improved KahanBabuska algorithm introduced by Neumaier.
let sum = 0;
// The "lost bits" of sum.
let c = 0;
for (let i = 0; i < input.length; i++) {
const cur = input[i];
const t = sum + cur;
if (Math.abs(sum) >= Math.abs(cur)) {
c += (sum - t) + cur;
} else {
c += (cur - t) + sum;
}
sum = t;
}
return sum + c;
}
/**
* Accurately returns the prefix sum of a list of floating point numbers.
* See https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements
* for more information.
* @param {number[]} input
* @returns {[number, number][]} The prefix sum of the input, such that
* output[i] = [sum of first i integers, error of the sum].
* The "true" prefix sum is equal to the sum of the pair of numbers, but it is
* explicitly returned as a pair of numbers to ensure that the error portion
* isn't lost when subtracting prefix sums.
*/
function prefix_float_sum(input) {
const prefix_sum = [[0, 0]];
let sum = 0;
let c = 0;
for (let i = 0; i < input.length; i++) {
const cur = input[i];
const t = sum + cur;
if (Math.abs(sum) >= Math.abs(cur)) {
c += (sum - t) + cur;
} else {
c += (cur - t) + sum;
}
sum = t;
prefix_sum.push([sum, c]);
}
return prefix_sum;
}
/* /*
* Probability Density Function of rates. * Probability Density Function of rates.
* Since the PDF is continuous*, we approximate it by a discrete probability function: * Since the PDF is continuous*, we approximate it by a discrete probability function:
* the value in range [(x - 0.5), (x + 0.5)) has a uniform probability * the value in range [x, x + 1) has a uniform probability
* prob[x - value_start]; * prob[x - value_start];
* *
* Note that we operate all rate on the (* RATE_MULTIPLIER) scale. * Note that we operate all rate on the (* RATE_MULTIPLIER) scale.
@ -68,17 +122,24 @@ function range_intersect_length(range1, range2) {
* space is too large to compute directly in JS. * space is too large to compute directly in JS.
*/ */
class PDF { class PDF {
/* /**
* Initialize a PDF in range [a, b], a and b can be non-integer. * Initialize a PDF in range [a, b], a and b can be non-integer.
* if uniform is true, then initialize the probability to be uniform, else initialize to a * if uniform is true, then initialize the probability to be uniform, else initialize to a
* all-zero (invalid) PDF. * all-zero (invalid) PDF.
* @param {number} a - Left end-point.
* @param {number} b - Right end-point end-point.
* @param {boolean} uniform - If true, initialise with the uniform distribution.
*/ */
constructor(a, b, uniform = true) { constructor(a, b, uniform = true) {
this.value_start = Math.round(a); // We need to ensure that [a, b] is fully contained in [value_start, value_end].
this.value_end = Math.round(b); /** @type {number} */
this.value_start = Math.floor(a);
/** @type {number} */
this.value_end = Math.ceil(b);
const range = [a, b]; const range = [a, b];
const total_length = range_length(range); const total_length = range_length(range);
this.prob = Array(this.value_end - this.value_start + 1); /** @type {number[]} */
this.prob = Array(this.value_end - this.value_start);
if (uniform) { if (uniform) {
for (let i = 0; i < this.prob.length; i++) { for (let i = 0; i < this.prob.length; i++) {
this.prob[i] = this.prob[i] =
@ -87,24 +148,35 @@ class PDF {
} }
} }
/**
* Calculates the interval represented by this.prob[idx]
* @param {number} idx - The index of this.prob
* @returns {[number, number]} The interval representing this.prob[idx].
*/
range_of(idx) { range_of(idx) {
// TODO: consider doing the "exclusive end" properly. // We intentionally include the right end-point of the range.
return [this.value_start + idx - 0.5, this.value_start + idx + 0.5 - 1e-9]; // The probability of getting exactly an endpoint is zero, so we can assume
// the "probability ranges" are "touching".
return [this.value_start + idx, this.value_start + idx + 1];
} }
min_value() { min_value() {
return this.value_start - 0.5; return this.value_start;
} }
max_value() { max_value() {
return this.value_end + 0.5 - 1e-9; return this.value_end;
} }
/**
* @returns {number} The sum of probabilities before normalisation.
*/
normalize() { normalize() {
const total_probability = this.prob.reduce((acc, it) => acc + it, 0); const total_probability = float_sum(this.prob);
for (let i = 0; i < this.prob.length; i++) { for (let i = 0; i < this.prob.length; i++) {
this.prob[i] /= total_probability; this.prob[i] /= total_probability;
} }
return total_probability;
} }
/* /*
@ -121,75 +193,95 @@ class PDF {
this.prob = []; this.prob = [];
return 0; return 0;
} }
start = Math.floor(start);
end = Math.ceil(end);
let prob = 0; const start_idx = start - this.value_start;
const start_idx = Math.round(start) - this.value_start; const end_idx = end - this.value_start;
const end_idx = Math.round(end) - this.value_start; for (let i = start_idx; i < end_idx; i++) {
for (let i = start_idx; i <= end_idx; i++) { this.prob[i] *= range_intersect_length(this.range_of(i), range);
const bucket_prob = this.prob[i] * range_intersect_length(this.range_of(i), range);
this.prob[i] = bucket_prob;
prob += bucket_prob;
} }
this.prob = this.prob.slice(start_idx, end_idx + 1); this.prob = this.prob.slice(start_idx, end_idx);
this.value_start = Math.round(start); this.value_start = start;
this.value_end = Math.round(end); this.value_end = end;
this.normalize();
return prob; // The probability that the value was in this range is equal to the total
// sum of "un-normalised" values in the range.
return this.normalize();
} }
/* /**
* Subtract the PDF by a uniform distribution in [rate_decay_min, rate_decay_max] * Subtract the PDF by a uniform distribution in [rate_decay_min, rate_decay_max]
* *
* For simplicity, we assume that rate_decay_min and rate_decay_max are both integers. * For simplicity, we assume that rate_decay_min and rate_decay_max are both integers.
* @param {number} rate_decay_min
* @param {number} rate_decay_max
* @returns {void}
*/ */
decay(rate_decay_min, rate_decay_max) { decay(rate_decay_min, rate_decay_max) {
const ret = new PDF( // In case the arguments aren't integers, round them to the nearest integer.
this.min_value() - rate_decay_max, this.max_value() - rate_decay_min, false); rate_decay_min = Math.round(rate_decay_min);
/* rate_decay_max = Math.round(rate_decay_max);
// O(n^2) naive algorithm for reference, which would be too slow. // The sum of this distribution with a uniform distribution.
for (let i = this.value_start; i <= this.value_end; i++) { // Let's assume that both distributions start at 0 and X = this dist,
const unit_prob = this.prob[i - this.value_start] / (rate_decay_max - rate_decay_min) / 2; // Y = uniform dist, and Z = X + Y.
for (let j = rate_decay_min; j < rate_decay_max; j++) { // Let's also assume that X is a "piecewise uniform" distribution, so
// ([i - 0.5, i + 0.5] uniform) - ([j, j + 1] uniform) // x(i) = this.prob[Math.floor(i)] - which matches our implementation.
// -> [i - j - 1.5, i + 0.5 - j] with a triangular PDF // We also know that y(i) = 1 / max(Y) - as we assume that min(Y) = 0.
// -> approximate by // In the end, we're interested in:
// [i - j - 1.5, i - j - 0.5] uniform & // Pr(i <= Z < i+1) where i is an integer
// [i - j - 0.5, i - j + 0.5] uniform // = int. x(val) * Pr(i-val <= Y < i-val+1) dval from 0 to max(X)
ret.prob[i - j - 1 - ret.value_start] += unit_prob; // Part A // = int. x(floor(val)) * Pr(i-val <= Y < i-val+1) dval from 0 to max(X)
ret.prob[i - j - ret.value_start] += unit_prob; // Part B // = sum val from 0 to max(X)-1
// x(val) * f_i(val) / max(Y)
// where f_i(val) =
// 0.5 if i-val = 0 or max(Y), so val = i-max(Y) or i
// 1.0 if 0 < i-val < max(Y), so i-max(Y) < val < i
// as x(val) is "constant" for each integer step, so we can consider the
// integral in integer steps.
// = sum val from max(0, i-max(Y)) to min(max(X)-1, i)
// x(val) * f_i(val) / max(Y)
// for example, max(X)=1, max(Y)=10, i=5
// = sum val from max(0, 5-10)=0 to min(1-1, 5)=0
// x(val) * f_i(val) / max(Y)
// = x(0) * 1 / 10
// Get a prefix sum / CDF of this so we can calculate sums in O(1).
const prefix = prefix_float_sum(this.prob);
const max_X = this.prob.length;
const max_Y = rate_decay_max - rate_decay_min;
const newProb = Array(this.prob.length + max_Y);
for (let i = 0; i < newProb.length; i++) {
// Note that left and right here are INCLUSIVE.
const left = Math.max(0, i - max_Y);
const right = Math.min(max_X - 1, i);
// We want to sum, in total, prefix[right+1], -prefix[left], and subtract
// the 0.5s if necessary.
// This may involve numbers of differing magnitudes, so use the float sum
// algorithm to sum these up.
const numbers_to_sum = [
prefix[right + 1][0], prefix[right + 1][1],
-prefix[left][0], -prefix[left][1],
];
if (left === i-max_Y) {
// Need to halve the left endpoint.
numbers_to_sum.push(-this.prob[left] / 2);
} }
if (right === i) {
// Need to halve the right endpoint.
// It's guaranteed that we won't accidentally "halve" twice,
// as that would require i-max_Y = i, so max_Y = 0 - which is
// impossible.
numbers_to_sum.push(-this.prob[right] / 2);
}
newProb[i] = float_sum(numbers_to_sum) / max_Y;
} }
*/
// Transform to "CDF"
for (let i = 1; i < this.prob.length; i++) {
this.prob[i] += this.prob[i - 1];
}
// Return this.prob[l - this.value_start] + ... + this.prob[r - 1 - this.value_start];
// This assume that this.prob is already transformed to "CDF".
const sum = (l, r) => {
l -= this.value_start;
r -= this.value_start;
if (l < 0) l = 0;
if (r > this.prob.length) r = this.prob.length;
if (l >= r) return 0;
return this.prob[r - 1] - (l == 0 ? 0 : this.prob[l - 1]);
};
for (let x = 0; x < ret.prob.length; x++) { this.prob = newProb;
// i - j - 1 - ret.value_start == x (Part A) this.value_start -= rate_decay_max;
// -> i = x + j + 1 + ret.value_start, j in [rate_decay_min, rate_decay_max) this.value_end -= rate_decay_min;
ret.prob[x] = sum(x + rate_decay_min + 1 + ret.value_start, x + rate_decay_max + 1 + ret.value_start); // No need to normalise, as it is guaranteed that the sum of this.prob is 1.
// i - j - ret.value_start == x (Part B)
// -> i = x + j + ret.value_start, j in [rate_decay_min, rate_decay_max)
ret.prob[x] += sum(x + rate_decay_min + ret.value_start, x + rate_decay_max + ret.value_start);
}
this.prob = ret.prob;
this.value_start = ret.value_start;
this.value_end = ret.value_end;
this.normalize();
} }
} }
@ -810,13 +902,14 @@ class Predictor {
* generate_possibilities(sell_prices, first_buy, previous_pattern) { * generate_possibilities(sell_prices, first_buy, previous_pattern) {
if (first_buy || isNaN(sell_prices[0])) { if (first_buy || isNaN(sell_prices[0])) {
for (var buy_price = 90; buy_price <= 110; buy_price++) { for (var buy_price = 90; buy_price <= 110; buy_price++) {
sell_prices[0] = sell_prices[1] = buy_price; const temp_sell_prices = sell_prices.slice();
temp_sell_prices[0] = temp_sell_prices[1] = buy_price;
if (first_buy) { if (first_buy) {
yield* this.generate_pattern_3(sell_prices); yield* this.generate_pattern_3(temp_sell_prices);
} else { } else {
// All buy prices are equal probability and we're at the outmost layer, // All buy prices are equal probability and we're at the outmost layer,
// so don't need to multiply_generator_probability here. // so don't need to multiply_generator_probability here.
yield* this.generate_all_patterns(sell_prices, previous_pattern) yield* this.generate_all_patterns(temp_sell_prices, previous_pattern)
} }
} }
} else { } else {

@ -259,6 +259,21 @@ const getPriceClass = function(buy_price, max) {
return ""; return "";
} }
const displayPercentage = function(fraction) {
if (Number.isFinite(fraction)) {
let percent = fraction * 100;
if (percent >= 1) {
return percent.toPrecision(3) + '%';
} else if (percent >= 0.01) {
return percent.toFixed(2) + '%';
} else {
return '<0.01%';
}
} else {
return '—'
}
}
const calculateOutput = function (data, first_buy, previous_pattern) { const calculateOutput = function (data, first_buy, previous_pattern) {
if (isEmpty(data)) { if (isEmpty(data)) {
$("#output").html(""); $("#output").html("");
@ -270,18 +285,18 @@ const calculateOutput = function (data, first_buy, previous_pattern) {
let buy_price = parseInt(buy_input.val()); let buy_price = parseInt(buy_input.val());
previous_pattern_number = "" previous_pattern_number = ""
for (let poss of analyzed_possibilities) { for (let poss of analyzed_possibilities) {
var out_line = "<tr><td class='table-pattern'>" + poss.pattern_description + "</td>" var out_line = "<tr><td class='table-pattern'>" + poss.pattern_description + "</td>";
const style_price = buy_price || poss.prices[0].min;
if (previous_pattern_number != poss.pattern_number) { if (previous_pattern_number != poss.pattern_number) {
previous_pattern_number = poss.pattern_number previous_pattern_number = poss.pattern_number
pattern_count = analyzed_possibilities pattern_count = analyzed_possibilities
.filter(val => val.pattern_number == poss.pattern_number) .filter(val => val.pattern_number == poss.pattern_number)
.length .length
percentage_display = percent => Number.isFinite(percent) ? ((percent * 100).toPrecision(3) + '%') : '—' out_line += `<td rowspan=${pattern_count}>${displayPercentage(poss.category_total_probability)}</td>`;
out_line += `<td rowspan=${pattern_count}>${percentage_display(poss.category_total_probability)}</td>`;
} }
out_line += `<td>${percentage_display(poss.probability)}</td>`; out_line += `<td>${displayPercentage(poss.probability)}</td>`;
for (let day of poss.prices.slice(1)) { for (let day of poss.prices.slice(2)) {
let price_class = getPriceClass(buy_price, day.max); let price_class = getPriceClass(style_price, day.max);
if (day.min !== day.max) { if (day.min !== day.max) {
out_line += `<td class='${price_class}'>${day.min} ${i18next.t("output.to")} ${day.max}</td>`; out_line += `<td class='${price_class}'>${day.min} ${i18next.t("output.to")} ${day.max}</td>`;
} else { } else {
@ -289,8 +304,8 @@ const calculateOutput = function (data, first_buy, previous_pattern) {
} }
} }
var min_class = getPriceClass(buy_price, poss.weekGuaranteedMinimum); var min_class = getPriceClass(style_price, poss.weekGuaranteedMinimum);
var max_class = getPriceClass(buy_price, poss.weekMax); var max_class = getPriceClass(style_price, poss.weekMax);
out_line += `<td class='${min_class}'>${poss.weekGuaranteedMinimum}</td><td class='${max_class}'>${poss.weekMax}</td></tr>`; out_line += `<td class='${min_class}'>${poss.weekGuaranteedMinimum}</td><td class='${max_class}'>${poss.weekMax}</td></tr>`;
output_possibilities += out_line output_possibilities += out_line
} }
@ -353,9 +368,6 @@ const update = function () {
const first_buy = getCheckedRadio(first_buy_radios) == 'true'; const first_buy = getCheckedRadio(first_buy_radios) == 'true';
const previous_pattern = parseInt(getCheckedRadio(previous_pattern_radios)); const previous_pattern = parseInt(getCheckedRadio(previous_pattern_radios));
buy_input[0].disabled = first_buy;
buy_input[0].placeholder = first_buy ? '—' : '...'
const permalink = generatePermalink(buy_price, sell_prices, first_buy, previous_pattern); const permalink = generatePermalink(buy_price, sell_prices, first_buy, previous_pattern);
if (permalink) { if (permalink) {
permalink_button.show(); permalink_button.show();

@ -3,6 +3,24 @@ function updateContent() {
$('body').localize(); $('body').localize();
} }
const defaultLanguage = 'en'; const defaultLanguage = 'en';
const LANGUAGES = {
'ca': 'Català',
'de': 'Deutsch',
'en': 'English',
'es': 'Español',
'fr': 'Français',
'hu': 'magyar',
'it': 'Italiano',
'ja': '日本語',
'ko': '한국어',
'nl': 'Nederlands',
'pl': 'Polski',
'pt-BR': 'Português',
'ru': 'Русский',
'th': 'ไทย',
'zh-CN': '简体中文',
'zh-TW': '繁體中文'
};
i18next i18next
.use(i18nextXHRBackend) .use(i18nextXHRBackend)
.use(i18nextBrowserLanguageDetector) .use(i18nextBrowserLanguageDetector)
@ -13,27 +31,16 @@ i18next
loadPath: 'locales/{{lng}}.json', loadPath: 'locales/{{lng}}.json',
}, },
}, (err, t) => { }, (err, t) => {
const languages = [
['de', 'Deutsch'],
['en', 'English'],
['es-ES', 'Español'],
['fr', 'Français'],
['hu', 'magyar'],
['it', 'Italiano'],
['ja', '日本語'],
['ko', '한국어'],
['nl', 'Nederlands'],
['pt-BR', 'Português'],
['ru', 'Русский'],
['zh-CN', '简体中文'],
['zh-TW', '繁體中文']
].sort(),
languageSelector = $('#language'); languageSelector = $('#language');
languages.map(([code, name]) => { for (let [code, name] of Object.entries(LANGUAGES)) {
languageSelector.append(`<option value="${code}"${code == i18next.language ? ' selected' : ''}>${name}</option>`); languageSelector.append(`<option value="${code}">${name}</option>`);
}); }
if (!languageSelector.find('[selected]').length) for (let code of i18next.languages) {
languageSelector.val(defaultLanguage); if (code in LANGUAGES) {
languageSelector.val(code);
break;
}
}
languageSelector.on('change', function () { languageSelector.on('change', function () {
if (this.value == i18next.language) if (this.value == i18next.language)
return; return;
@ -41,15 +48,21 @@ i18next
}); });
jqueryI18next.init(i18next, $); jqueryI18next.init(i18next, $);
i18next.on('languageChanged', lng => { i18next.on('languageChanged', lng => {
if (!languageSelector.find(`[value=${lng}]`).length) {
i18next.changeLanguage(defaultLanguage);
return;
}
languageSelector.val(lng);
updateContent(); updateContent();
}); });
// init set content // init set content
$(document).ready(initialize); $(document).ready(initialize);
$(document).on('input', updateContent);
let delayTimer;
$(document).on('input', function(event) {
//prevent radio input from updating content twice per input change
if(event.target.type === 'radio'){ return }
// adding short delay after input to help mitigate potential lag after keystrokes
clearTimeout(delayTimer);
delayTimer = setTimeout(function() {
updateContent();
}, 500);
});
$('input[type = radio]').on('change', updateContent); $('input[type = radio]').on('change', updateContent);
}); });

@ -0,0 +1,81 @@
{
"general": {
"daisy-mae": "Juliana"
},
"welcome": {
"salutation": "Hola! Et donem la benvinguda a l'app <b>Turnip Prophet</b> pel teu Nookòfon.",
"description": "Aquesta app et permet predir els preus dels naps a la teva illa, però hauràs d'introduir-hi tu els preus passats!",
"conclusion": "Fet això, l'app Turnip Prophet <b>endevinarà</b> els preus que tindràs durant la resta de la setmana."
},
"first-time": {
"title": "Primer cop que compres",
"description": "És la primera vegada que li compres naps a la Juliana a la <b>teva</b> illa?<i>(Afecta al patró de preus)</i>",
"yes": "Sí",
"no": "No"
},
"patterns": {
"title": "Patró anterior",
"description": "Quin patró tenien els teus preus la setmana passada?<i>(Afecta al patró actual)</i>",
"pattern": "Patró",
"all": "Tots els patrons",
"decreasing": "Decreixent",
"fluctuating": "Fluctuant",
"unknown": "No ho sé",
"large-spike": "Pic gran",
"small-spike": "Pic petit"
},
"prices": {
"description": "Quin ha sigut el preu de compra de naps a la teva illa aquesta setmana?",
"open": {
"am": "AM - De les 8:00 am a les 11:59 am",
"pm": "PM - De les 12:00 pm a les 10:00 pm"
},
"copy-permalink": "Copiar permalink",
"permalink-copied": "Permalink copiat!",
"reset": "Reiniciar Turnip Prophet",
"reset-warning": "Segur que vols reiniciar tots els camps?\n\nNo pots desfer aquesta acció!"
},
"weekdays": {
"monday": "Dilluns",
"tuesday": "Dimarts",
"wednesday": "Dimecres",
"thursday": "Dijous",
"friday": "Divendres",
"saturday" : "Dissabte",
"sunday": "Diumenge",
"abr": {
"monday": "Dl",
"tuesday": "Dm",
"wednesday": "Dc",
"thursday": "Dj",
"friday": "Dv",
"saturday" : "Ds"
}
},
"times": {
"morning": "AM",
"afternoon": "PM"
},
"output": {
"title": "Resultat",
"chance": "Probabilitat (%)",
"to": "a",
"minimum": "Mínim garantit",
"maximum": "Màxim potencial",
"chart": {
"input": "Preu d'entrada",
"minimum": "Mínim garantit",
"maximum": "Màxim potencial"
}
},
"textbox": {
"description": "Quan hagis posat els preus dels naps, el Turnip Prophet farà comptes i et mostrarà els possibles patrons que puguin haver a la teva illa.",
"development": "L'app encara està en desenvolupament, però l'anirem millorant!",
"thanks": "Aquest projecte ha estat possible gràcies a en <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji</a>, que va descobrir com calculen en Tendo i en Nendo els preus dels naps.",
"support": "A <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a> hi trobaràs suport, comentaris, i contribucions.",
"sponsor": "Vols patrocinar als desenvolupadors del projecte? Ves a <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub</a> i clica damunt de '❤ Sponsor'",
"contributors-text": "Ah! I no ens oblidem dels que ja han ajudat amb les seves contribucions!",
"contributors": "Contribuidors",
"language": "Llenguatge"
}
}

@ -25,7 +25,7 @@
"small-spike": "Leicht Ansteigend" "small-spike": "Leicht Ansteigend"
}, },
"prices": { "prices": {
"description": "Wie hoch war der Preis für Rüben diese Woche auf deiner Insel? <i>(Wenn du zum ersten Mal Rüben kaufst, wird dieses Feld deaktiviert)</i>", "description": "Wie hoch war der Preis für Rüben diese Woche auf deiner Insel?",
"open": { "open": {
"am": "Vorm. (Vormittag) - 8:00 Uhr bis 11:59 Uhr", "am": "Vorm. (Vormittag) - 8:00 Uhr bis 11:59 Uhr",
"pm": "Nachm. (Nachmittag) - 12:00 Uhr bis 22:00 Uhr" "pm": "Nachm. (Nachmittag) - 12:00 Uhr bis 22:00 Uhr"
@ -73,6 +73,7 @@
"development": "Diese App befindet sich noch in der Entwicklung, wird sich aber mit der Zeit verbessern!", "development": "Diese App befindet sich noch in der Entwicklung, wird sich aber mit der Zeit verbessern!",
"thanks": "Nichts von all dem wäre möglich gewesen, ohne das <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji</a> herausgefunden hätte, wie Nepp und Schlepp ihre Rübenpreise kalkulieren.", "thanks": "Nichts von all dem wäre möglich gewesen, ohne das <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji</a> herausgefunden hätte, wie Nepp und Schlepp ihre Rübenpreise kalkulieren.",
"support": "Hilfe, Kommentare und Beiträge sind auffindbar über <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">GitHub.com</a> (nur in Englisch).", "support": "Hilfe, Kommentare und Beiträge sind auffindbar über <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">GitHub.com</a> (nur in Englisch).",
"sponsor": "Möchtest du die Entwickler hinter diesem Projekt unterstützen? Gehe zu <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub.com</a> und klicke auf den '❤ Sponsor' Button für mehr Informationen.",
"contributors-text": "Oh! Und vergessen wir nicht, denen zu danken, die bis jetzt dazu beigetragen haben!", "contributors-text": "Oh! Und vergessen wir nicht, denen zu danken, die bis jetzt dazu beigetragen haben!",
"contributors": "Mitwirkende", "contributors": "Mitwirkende",
"language": "Sprache" "language": "Sprache"

@ -9,7 +9,7 @@
}, },
"first-time": { "first-time": {
"title": "First-Time Buyer", "title": "First-Time Buyer",
"description": "Is this your first time buying turnips from Daisy Mae on your island?<i>(This affects your pattern)</i>", "description": "Is this the first time a resident is buying turnips from Daisy Mae on <b>your own</b> island?<i>(This affects your pattern)</i>",
"yes": "Yes", "yes": "Yes",
"no": "No" "no": "No"
}, },
@ -25,7 +25,7 @@
"small-spike": "Small Spike" "small-spike": "Small Spike"
}, },
"prices": { "prices": {
"description": "What was the price of turnips this week on your island? <i>(If this is your first time buying turnips, this field will be disabled)</i>", "description": "What was the price of turnips this week on your island?",
"open": { "open": {
"am": "AM - 8:00 am to 11:59 am", "am": "AM - 8:00 am to 11:59 am",
"pm": "PM - 12:00 pm to 10:00 pm" "pm": "PM - 12:00 pm to 10:00 pm"
@ -73,6 +73,7 @@
"development": "This app is still in development, but will improve over time!", "development": "This app is still in development, but will improve over time!",
"thanks": "None of this would have been possible without <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji's work</a> figuring out just how Timmy and Tommy value their turnips.", "thanks": "None of this would have been possible without <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji's work</a> figuring out just how Timmy and Tommy value their turnips.",
"support": "Support, comments and contributions are available through <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>", "support": "Support, comments and contributions are available through <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>",
"sponsor": "Want to sponsor the developers behind this project? Go to the <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub</a> page and click '❤ Sponsor'",
"contributors-text": "Oh! And let's not forget to thank those who have contributed so far!", "contributors-text": "Oh! And let's not forget to thank those who have contributed so far!",
"contributors": "Contributors", "contributors": "Contributors",
"language": "Language" "language": "Language"

@ -25,7 +25,7 @@
"small-spike": "Pico moderado" "small-spike": "Pico moderado"
}, },
"prices": { "prices": {
"description": "¿Cuál fue el precio de los nabos en su isla esta semana? <i>(Si esta ha sido tu primera vez comprando nabos, este campo se desactivará)</i>", "description": "¿Cuál fue el precio de los nabos en su isla esta semana?",
"open": { "open": {
"am": "AM - De 8:00 a 11:59", "am": "AM - De 8:00 a 11:59",
"pm": "PM - De 12:00 a 22:00" "pm": "PM - De 12:00 a 22:00"

@ -25,7 +25,7 @@
"small-spike": "Petit Pic" "small-spike": "Petit Pic"
}, },
"prices": { "prices": {
"description": "À quel prix Porcelette vendait ses navets sur ton île cette semaine ?<i>(Si c'est la première fois que t'en achètes, ce champ sera desactivé)</i>", "description": "À quel prix Porcelette vendait ses navets sur ton île cette semaine ?",
"open": { "open": {
"am": "Matin (AM) - de 8:00 à 11:59", "am": "Matin (AM) - de 8:00 à 11:59",
"pm": "Après-midi (PM) - de 12:00 à 22:00" "pm": "Après-midi (PM) - de 12:00 à 22:00"
@ -73,8 +73,9 @@
"development": "Cette appli est en développement, mais elle s'améliore jour après jour !", "development": "Cette appli est en développement, mais elle s'améliore jour après jour !",
"thanks": "Rien de tout ça n'aurait pu être possible sans <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">le travail de Ninji</a> et son analyse sur comment Méli et Mélo déterminent la valeur des Navets.", "thanks": "Rien de tout ça n'aurait pu être possible sans <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">le travail de Ninji</a> et son analyse sur comment Méli et Mélo déterminent la valeur des Navets.",
"support": "Aide, commentaires et contributions sont disponibles via <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>", "support": "Aide, commentaires et contributions sont disponibles via <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>",
"sponsor": "T'aimerais sponsoriser les développeurs derrière ce projet ? Alors va sur la page <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub</a> du projet et clique sur '❤ Sponsor'",
"contributors-text": "Oh ! Et n'oublions pas de remercier toutes les personnes ayant contribué jusqu'à maintenant !", "contributors-text": "Oh ! Et n'oublions pas de remercier toutes les personnes ayant contribué jusqu'à maintenant !",
"contributors": "Contributeurs", "contributors": "Contributeurs",
"language": "Langue" "language": "Langue"
} }
} }

@ -9,7 +9,7 @@
}, },
"first-time": { "first-time": {
"title": "Első vásárlás", "title": "Első vásárlás",
"description": "Most vásárolsz retket Daisy Mae-től a szigeteden először?<i>(Ez hatással van a mintádra)</i>", "description": "Most vásárol valaki először retket Daisy Mae-től a <b>Te szigeteden</b>?<i>(Ez hatással van a mintádra)</i>",
"yes": "Igen", "yes": "Igen",
"no": "Nem" "no": "Nem"
}, },
@ -25,10 +25,10 @@
"small-spike": "Kis kiugrás" "small-spike": "Kis kiugrás"
}, },
"prices": { "prices": {
"description": "Mennyiért vettél ezen a héten retket? <i>(Ha most vásárolsz először, ez a mező le lesz tiltva)</i>", "description": "Mennyiért vettél ezen a héten retket?",
"open": { "open": {
"am": "Délelőtt - 08:00-tól 11:59-ig", "am": "Délelőtt - 08:00-tól 11:59-ig",
"pm": "Délután - 12:00-tól 22:00-ig" "pm": "Délután - 12:00-től 22:00-ig"
}, },
"copy-permalink": "Árak megosztása", "copy-permalink": "Árak megosztása",
"permalink-copied": "Hivatkozás kimásolva!", "permalink-copied": "Hivatkozás kimásolva!",
@ -73,6 +73,7 @@
"development": "Ez az alkalmazás fejlesztés alatt áll, de idővel javulni fog!", "development": "Ez az alkalmazás fejlesztés alatt áll, de idővel javulni fog!",
"thanks": "Ez nem lett volna lehetséges <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji munkája</a> nélkül, aki megfejtette, hogy Timmy és Tommy hogyan árazzák a retket.", "thanks": "Ez nem lett volna lehetséges <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji munkája</a> nélkül, aki megfejtette, hogy Timmy és Tommy hogyan árazzák a retket.",
"support": "Minden hibajelentést, megjegyzést és hozzájárulást a <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github-on</a> várunk.", "support": "Minden hibajelentést, megjegyzést és hozzájárulást a <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github-on</a> várunk.",
"sponsor": "Szeretnéd szponzorálni a projekt fejlesztőit? Menj a <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub</a> oldalra és nyomd meg a „❤ Sponsor” gombot!",
"contributors-text": "Ó, és ne felejtsünk el köszönetet mondani az eddigi hozzájárulóknak!", "contributors-text": "Ó, és ne felejtsünk el köszönetet mondani az eddigi hozzájárulóknak!",
"contributors": "Hozzájárulók", "contributors": "Hozzájárulók",
"language": "Nyelv" "language": "Nyelv"

@ -26,7 +26,7 @@
"small-spike": "Piccolo picco" "small-spike": "Piccolo picco"
}, },
"prices": { "prices": {
"description": "Qual era il prezzo di acquisto delle rape sulla tua isola questa settimana? <i>(Se è la prima volta che le compri questo campo è disabilitato)</i>", "description": "Qual era il prezzo di acquisto delle rape sulla tua isola questa settimana?",
"open": { "open": {
"am": "Mattina - dalle 8:00 alle 11:59", "am": "Mattina - dalle 8:00 alle 11:59",
"pm": "Pomeriggio - dalle 12:00 alle 22:00" "pm": "Pomeriggio - dalle 12:00 alle 22:00"
@ -74,7 +74,9 @@
"development": "Quest'applicazione è in ancora in sviluppo ma migliorerà col tempo!", "development": "Quest'applicazione è in ancora in sviluppo ma migliorerà col tempo!",
"thanks": "Niente di questo sarebbe possibile senza <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">il lavoro di Ninji</a> nello scoprire come Mirko e Marco valutano le rape.", "thanks": "Niente di questo sarebbe possibile senza <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">il lavoro di Ninji</a> nello scoprire come Mirko e Marco valutano le rape.",
"support": "Chiedi supporto o lascia commenti e contributi su <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>", "support": "Chiedi supporto o lascia commenti e contributi su <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>",
"sponsor": "Vuoi sponsorizzare gli sviluppatori di questo progetto? Vai nella pagina <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub</a> e clicca '❤ Sponsor'",
"contributors-text": "Oh! Non dimentichiamoci di ringraziare chi ha contribuito fin'ora!", "contributors-text": "Oh! Non dimentichiamoci di ringraziare chi ha contribuito fin'ora!",
"contributors": "Collaboratori" "contributors": "Collaboratori",
"language": "Lingua"
} }
} }

@ -25,7 +25,7 @@
"small-spike": "跳ね小型(4期型)" "small-spike": "跳ね小型(4期型)"
}, },
"prices": { "prices": {
"description": "今週のカブ価は? <i>(初めてカブを購入した場合は、この入力欄は無効にされています)</i>", "description": "今週のカブ価は?",
"open": { "open": {
"am": "午前 - AM 8:00 AM 11:59", "am": "午前 - AM 8:00 AM 11:59",
"pm": "午後 - PM 12:00 PM 10:00" "pm": "午後 - PM 12:00 PM 10:00"

@ -25,7 +25,7 @@
"small-spike": "작은 급등" "small-spike": "작은 급등"
}, },
"prices": { "prices": {
"description": "이번 주에 당신의 섬에서 무를 샀을 때의 가격이 어떻게 됩니까? <i>(첫 구매인 경우에는 입력란이 비활성화됩니다)</i>", "description": "이번 주에 당신의 섬에서 무를 샀을 때의 가격이 어떻게 됩니까?",
"open": { "open": {
"am": "오전 - 오전 8:00 ~ 오전 11:59", "am": "오전 - 오전 8:00 ~ 오전 11:59",
"pm": "오후 - 오후 12:00 ~ 오후 10:00" "pm": "오후 - 오후 12:00 ~ 오후 10:00"

@ -25,7 +25,7 @@
"small-spike": "Kleine Piek" "small-spike": "Kleine Piek"
}, },
"prices": { "prices": {
"description": "Wat was de prijs van knollen op je eiland deze week? <i>(Als dit de eerste keer is dat je knollen koopt is dit veld uitgeschakeld)</i>", "description": "Wat was de prijs van knollen op je eiland deze week?",
"open": { "open": {
"am": "Voormiddag - 8:00 tot 11:59", "am": "Voormiddag - 8:00 tot 11:59",
"pm": "Namiddag - 12:00 tot 22:00" "pm": "Namiddag - 12:00 tot 22:00"
@ -73,6 +73,7 @@
"development": "Deze applicatie is wordt nog ontwikkeld, maar zal met de tijd beter worden!", "development": "Deze applicatie is wordt nog ontwikkeld, maar zal met de tijd beter worden!",
"thanks": "Dit alles zou niet mogelijk zijn zonder het <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">werk van Ninji</a> om uit te zoeken hoe Timmy en Tommy de waarde van knollen bepalen.", "thanks": "Dit alles zou niet mogelijk zijn zonder het <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">werk van Ninji</a> om uit te zoeken hoe Timmy en Tommy de waarde van knollen bepalen.",
"support": "Ondersteuning, feedback en bijdrages zijn mogelijk via <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>", "support": "Ondersteuning, feedback en bijdrages zijn mogelijk via <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>",
"sponsor": "Wil je de ontwikkelaars van dit project sponsoren? Ga naar de <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub</a> pagina en klik op '❤ Sponsor'",
"contributors-text": "Oh! En laten we degenen die tot nu toe bijgedragen hebben niet vergeten te bedanken!", "contributors-text": "Oh! En laten we degenen die tot nu toe bijgedragen hebben niet vergeten te bedanken!",
"contributors": "Bijdragers", "contributors": "Bijdragers",
"language": "Taal" "language": "Taal"

@ -0,0 +1,81 @@
{
"general": {
"daisy-mae": "Daisy Mae"
},
"welcome": {
"salutation": "Cześć, witam w aplikacji <b>Turnip Prophet</b> na Twoim Nook Phone.",
"description": "Ta aplikacja pozwoli Ci codziennie śledzić ceny rzep na twojej wyspie, jednak będziesz musiał uzupełniać je samodzielnie.",
"conclusion": "Następnie aplikacja Turnip Prophet <b>w magiczny sposób</b> przewidzi jakie ceny rzep będziesz mieć przez resztę tygodnia"
},
"first-time": {
"title": "Kupujący po raz pierwszy",
"description": "Czy jest to pierwszy raz gdy kupujesz rzepy od Daisy Mae na <b>własnej</b> wyspie?<i>(Ta opcja wpłynie na Twój schemat)</i>",
"yes": "Tak",
"no": "Nie"
},
"patterns": {
"title": "Poprzedni schemat",
"description": "Jaka była tendencja cen rzep w poprzednim tygodniu?<i>(Ta opcja wpłynie na Twój wzór)</i>",
"pattern": "Wzór",
"all": "Wszystkie wzory",
"decreasing": "Malejąca",
"fluctuating": "Zmienna",
"unknown": "Nie pamiętam",
"large-spike": "Duży wzrost",
"small-spike": "Mały wzrost"
},
"prices": {
"description": "Jakie ceny za rzepy były w tym tygodniu na Twojej wyspie?",
"open": {
"am": "Przed południem - 8:00 do 11:59 ",
"pm": "Po południu - 12:00 do 22:00 "
},
"copy-permalink": "Skopiuj permalink",
"permalink-copied": "Permalink skopiowany!",
"reset": "Wyzeruj Turnip Prophet",
"reset-warning": "Czy jesteś pewien, że chcesz wyzerować wszystkie pola?\n\nTej opcji nie można cofnąć!"
},
"weekdays": {
"monday": "Poniedziałek",
"tuesday": "Wtorek",
"wednesday": "Środa",
"thursday": "Czwartek",
"friday": "Piątek",
"saturday" : "Sobota",
"sunday": "Niedziela",
"abr": {
"monday": "Pon",
"tuesday": "Wt",
"wednesday": "Śr",
"thursday": "Czw",
"friday": "Pt",
"saturday" : "Sob"
}
},
"times": {
"morning": "Rano",
"afternoon": "Południe"
},
"output": {
"title": "Wyniki",
"chance": "Szansa %",
"to": "do",
"minimum": "Gwarantowana cena minimalna",
"maximum": "Potencjalna najwyższa cena",
"chart": {
"input": "Cena wejściowa",
"minimum": "Gwarantowana cena minimalna",
"maximum": "Potencjalna najwyższa cena"
}
},
"textbox": {
"description": "Po tym jak wprowadzisz kilka cen rzep, Turnip Prophet dokona obliczeń i wyświetli różne prawdopodobne szablony cen, których może doświadczyć Twoja wyspa",
"development": "Ta aplikacja wciąż jest w produkcji, lecz z czasem zostanie poprawiona!",
"thanks": "Nie udałoby nam się to bez <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">pracy Ninji</a>, który dowiedział się jak Timmy and Tommy wyceniają rzepy.",
"support": "Wsparcie, komentarze i wpłaty są możliwe pod adresem <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>",
"sponsor": "Chcesz, wesprzeć twórców tego projektu? Wejdź na stronę <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub</a> i wciśnij '❤ Sponsor'",
"contributors-text": "Oh! I nie zapominajmy o tych, którzy dotychczas nas wspierali!",
"contributors": "Fundatorzy",
"language": "Język"
}
}

@ -25,7 +25,7 @@
"small-spike": "Pequeno Pico" "small-spike": "Pequeno Pico"
}, },
"prices": { "prices": {
"description": "Qual foi o preço dos nabos esta semana em sua ilha? <i>(Se esta é a primeira vez que compra nabos, este campo ficará desativado)</i>", "description": "Qual foi o preço dos nabos esta semana em sua ilha?",
"open": { "open": {
"am": "AM - 8:00 am até 11:59 am", "am": "AM - 8:00 am até 11:59 am",
"pm": "PM - 12:00 pm até 10:00 pm" "pm": "PM - 12:00 pm até 10:00 pm"

@ -25,7 +25,7 @@
"small-spike": "Малый скачок" "small-spike": "Малый скачок"
}, },
"prices": { "prices": {
"description": "Какова была стоимость репы у Дейзи Мэй на Вашем острове на этой неделе? <i>(Если вы новичок рынка репы, данное поле будет недоступно)</i>", "description": "Какова была стоимость репы у Дейзи Мэй на Вашем острове на этой неделе?",
"open": { "open": {
"am": "Утро - 8:00 - 11:59", "am": "Утро - 8:00 - 11:59",
"pm": "День - 12:00 - 22:00" "pm": "День - 12:00 - 22:00"
@ -73,6 +73,7 @@
"development": "Это приложение пока еще в разработке, но со временем обязательно станет лучше!", "development": "Это приложение пока еще в разработке, но со временем обязательно станет лучше!",
"thanks": "Если бы <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji</a> не смог разузнать, как Тимми и Томми определяют стоимость репы, данного приложения могло бы и не быть!", "thanks": "Если бы <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji</a> не смог разузнать, как Тимми и Томми определяют стоимость репы, данного приложения могло бы и не быть!",
"support": "Поддержать нас, прокомментировать, а также внести свой вклад Вы можете на <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>", "support": "Поддержать нас, прокомментировать, а также внести свой вклад Вы можете на <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>",
"sponsor": "Хотели бы поддержать разработчиков проекта? Для этого Вы можете перейти на <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub</a> и нажать '❤ Sponsor'",
"contributors-text": "Точно! Нельзя забывать тех, кто уже помог проекту!", "contributors-text": "Точно! Нельзя забывать тех, кто уже помог проекту!",
"contributors": "Вклад внесли", "contributors": "Вклад внесли",
"language": "Язык" "language": "Язык"

@ -0,0 +1,81 @@
{
"general": {
"daisy-mae": "Daisy Mae"
},
"welcome": {
"salutation": "สวัสดีจ้า ยินดีต้อนรับสู่โปรแกรม <b>Turnip Prophet</b> บน Nook Phone ของคุณ",
"description": "โปรแกรมนี้จะช่วยให้คุณสามารถจดบันทึกราคาหัวผักกาดรายวันบนเกาะของคุณ แต่ต้องจดเองนะ!",
"conclusion": "หลังจากนั้น Turnip Prophet จะทำการ<b>พยากรณ์</b>ราคาหัวผักกาดตลอดทั้งสัปดาห์ที่เป็นไปได้ให้คุณ"
},
"first-time": {
"title": "ซื้อครั้งแรก",
"description": "นี่เป็นครั้งแรกที่คุณซื้อหัวผักกาดจากน้องหมูอู๊ดๆ Daisy Mae บนเกาะ<b>ของคุณรีเปล่า</b>?<i>(มีผลกับการคำนวณรูปแบบราคา)</i>",
"yes": "ใช่",
"no": "ไม่"
},
"patterns": {
"title": "รูปแบบก่อนหน้า",
"description": "รูปแบบของราคาสัปดาห์ที่แล้ว?<i>(มีผลกับการคำนวณรูปแบบราคา)</i>",
"pattern": "รูปแบบ",
"all": "รูปแบบทั้งหมด",
"decreasing": "ลดลง",
"fluctuating": "ผันผวน",
"unknown": "ไม่รู้สิ!",
"large-spike": "พุ่งขึ้นสูงมาก",
"small-spike": "พุ่งขึ้นเล็กน้อย"
},
"prices": {
"description": "ราคาหัวผักกาดบนเกาะของคุณสัปดาห์นี้?",
"open": {
"am": "เช้า - 08.00 นาฬิกา ถึง 11.59 นาฬิกา",
"pm": "บ่าย - 12:00 นาฬิกา to 22:00 นาฬิกา"
},
"copy-permalink": "คัดลอก Permalink",
"permalink-copied": "Permalink คัดลอกแล้วจ้า!",
"reset": "รีเซ็ต Turnip Prophet",
"reset-warning": "แน่ใจนะว่าจะล้างข้อมูลทั้งหมด?\n\nแก้ไขอีกไม่ได้แล้วนา!"
},
"weekdays": {
"monday": "วันจันทร์",
"tuesday": "วันอังคาร",
"wednesday": "วันพุธ",
"thursday": "วันพฤหัสบดี",
"friday": "วันศุกร์",
"saturday" : "วันเสาร์",
"sunday": "วันอาทิตย์",
"abr": {
"monday": "จันทร์",
"tuesday": "อังคาร",
"wednesday": "พุธ",
"thursday": "พฤหัส",
"friday": "ศุกร์",
"saturday" : "เสาร์"
}
},
"times": {
"morning": "เช้า",
"afternoon": "บ่าย"
},
"output": {
"title": "ผลลัพธ์",
"chance": "โอกาส %",
"to": "ถึง",
"minimum": "การันตีต่ำสุด",
"maximum": "เป็นไปได้สูงสุด",
"chart": {
"input": "ราคา",
"minimum": "การันตีต่ำสุด",
"maximum": "เป็นไปได้สูงสุด"
}
},
"textbox": {
"description": "หลังจากใส่ราคาหัวผักกาดไปได้บางส่วน โปรแกรม Turnip Prophet จะทำการแสดงตัวเลขราคาและความเป็นไปได้ของรูปแบบต่าง ๆ ที่เกาะของคุณจะเจอ",
"development": "โปรแกรมนี้ยังอยู่ในขั้นตอนพัฒนา แต่จะค่อยๆปรับปรุงขึ้นเรื่อยๆ!",
"thanks": "ทั้งหมดนี้ไม่อาจเกิดขึ้นได้เลยถ้าปราศจากผลงานของ <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji</a> ที่ค้นพบวิธีการให้ราคาหัวผักกาดของทานุกิน้อย Timmy และ Tommy",
"support": "สนับสนุน, แสดงความเห็นและช่วยพัฒนาได้ที่ <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>",
"sponsor": "ต้องการเป็นสปอนเซอร์แก่นักพัฒนา? ไปที่ <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub</a> และเลือก '❤ Sponsor'",
"contributors-text": "อ้อ! และต้องไม่ลืมที่จะขอบคุณผู้ที่ช่วยร่วมพัฒนามาจนถึงตอนนี้!",
"contributors": "ผู้ร่วมพัฒนา",
"language": "ภาษา"
}
}

@ -25,7 +25,7 @@
"small-spike": "小幅上涨(四期型)" "small-spike": "小幅上涨(四期型)"
}, },
"prices": { "prices": {
"description": "本周你的岛上大头菜的购买价格是多少?<i>(如果你是第一次购买大头菜,这个字段不可用)</i>", "description": "本周你的岛上大头菜的购买价格是多少?",
"open": { "open": {
"am": "上午 - 8:00 ~ 11:59", "am": "上午 - 8:00 ~ 11:59",
"pm": "下午 - 12:00 ~ 22:00" "pm": "下午 - 12:00 ~ 22:00"
@ -71,8 +71,9 @@
"textbox": { "textbox": {
"description": "在填写一些大头菜价格后,大头菜预测工具将预测大头菜的价格并显示本周可能的趋势。", "description": "在填写一些大头菜价格后,大头菜预测工具将预测大头菜的价格并显示本周可能的趋势。",
"development": "APP仍在开发中但会随着时间的推移不断完善", "development": "APP仍在开发中但会随着时间的推移不断完善",
"thanks": "如果不是<a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji</a>发现豆狸和粒狸如何给大头菜定价的,这一切将不可能实现。", "thanks": "如果不是 <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji</a> 发现豆狸和粒狸如何给大头菜定价的,这一切将不可能实现。",
"support": "可以在<a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a>获得支持,或讨论和贡献", "support": "可以在 <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">Github</a> 获得支持,或讨论和贡献",
"sponsor": "想要赞助这个项目的开发者?进入 <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub</a> 并点击 ❤ Sponsor",
"contributors-text": "哦!别忘记感谢那些至今为止做出过贡献的人。", "contributors-text": "哦!别忘记感谢那些至今为止做出过贡献的人。",
"contributors": "贡献者", "contributors": "贡献者",
"language": "语言" "language": "语言"

@ -25,7 +25,7 @@
"small-spike": "四期型" "small-spike": "四期型"
}, },
"prices": { "prices": {
"description": "本週自己島上的大頭菜買價?<i>(若這是你第一次購買大頭菜,則此欄位會被停用)</i>", "description": "本週自己島上的大頭菜買價?",
"open": { "open": {
"am": "上午 - 08:00 到 11:59", "am": "上午 - 08:00 到 11:59",
"pm": "下午 - 12:00 到 22:00" "pm": "下午 - 12:00 到 22:00"
@ -73,6 +73,7 @@
"development": "此工具仍在開發中,但會隨著時間的推移而改善!", "development": "此工具仍在開發中,但會隨著時間的推移而改善!",
"thanks": "要不是 <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji</a> 協助釐清豆狸和粒狸的大頭菜估價方式,這一切都不可能實現。", "thanks": "要不是 <a href=\"https://twitter.com/_Ninji/status/1244818665851289602?s=20\">Ninji</a> 協助釐清豆狸和粒狸的大頭菜估價方式,這一切都不可能實現。",
"support": "可於 <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">GitHub</a> 取得支援、討論及貢獻。", "support": "可於 <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices/issues\">GitHub</a> 取得支援、討論及貢獻。",
"sponsor": "想要贊助這個專案的開發者?進入 <a href=\"https://github.com/mikebryant/ac-nh-turnip-prices#sponsor-button-repo\">GitHub</a> 並點擊 ❤ Sponsor",
"contributors-text": "嘿!別忘了感謝那些迄今為止作出貢獻的人!", "contributors-text": "嘿!別忘了感謝那些迄今為止作出貢獻的人!",
"contributors": "貢獻者", "contributors": "貢獻者",
"language": "語言" "language": "語言"

Loading…
Cancel
Save