| 1 | /* Copyright (c) 2008 Google Inc. | |
| 2 | * | |
| 3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 | * you may not use this file except in compliance with the License. | |
| 5 | * You may obtain a copy of the License at | |
| 6 | * | |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 | * | |
| 9 | * Unless required by applicable law or agreed to in writing, software | |
| 10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 | * See the License for the specific language governing permissions and | |
| 13 | * limitations under the License. | |
| 14 | */ | |
| 15 | ||
| 16 | package org.yaml.snakeyaml.external.com.google.gdata.util.common.base; | |
| 17 | ||
| 18 | import java.io.IOException; | |
| 19 | ||
| 20 | /** | |
| 21 | * An {@link Escaper} that converts literal text into a format safe for | |
| 22 | * inclusion in a particular context (such as an XML document). Typically (but | |
| 23 | * not always), the inverse process of "unescaping" the text is performed | |
| 24 | * automatically by the relevant parser. | |
| 25 | * | |
| 26 | *
 | |
| 27 | * For example, an XML escaper would convert the literal string | |
| 28 | * {@code "Foo<Bar>"} into {@code "Foo<Bar>"} to prevent {@code "<Bar>"} | |
| 29 | * from being confused with an XML tag. When the resulting XML document is | |
| 30 | * parsed, the parser API will return this text as the original literal string | |
| 31 | * {@code "Foo<Bar>"}. | |
| 32 | * | |
| 33 | *
 | |
| 34 | * Note: This class is similar to {@link CharEscaper} but with one very | |
| 35 | * important difference. A CharEscaper can only process Java UTF16 characters in isolation | |
| 37 | * and may not cope when it encounters surrogate pairs. This class facilitates | |
| 38 | * the correct escaping of all Unicode characters. | |
| 39 | * | |
| 40 | *
 | |
| 41 | * As there are important reasons, including potential security issues, to | |
| 42 | * handle Unicode correctly if you are considering implementing a new escaper | |
| 43 | * you should favor using UnicodeEscaper wherever possible. | |
| 44 | * | |
| 45 | *
 | |
| 46 | * A {@code UnicodeEscaper} instance is required to be stateless, and safe when | |
| 47 | * used concurrently by multiple threads. | |
| 48 | * | |
| 49 | *
 | |
| 50 | * Several popular escapers are defined as constants in the class | |
| 51 | * {@link CharEscapers}. To create your own escapers extend this class and | |
| 52 | * implement the {@link #escape(int)} method. | |
| 53 | * | |
| 54 | * | |
| 55 | */ | |
| 56 | public abstract class UnicodeEscaper implements Escaper { | |
| 57 | /** The amount of padding (chars) to use when growing the escape buffer. */ | |
| 58 | private static final int DEST_PAD = 32; | |
| 59 | ||
| 60 | /** | |
| 61 | * Returns the escaped form of the given Unicode code point, or {@code null} | |
| 62 | * if this code point does not need to be escaped. When called as part of an | |
| 63 | * escaping operation, the given code point is guaranteed to be in the range | |
| 64 | * {@code 0 <= cp <= Character#MAX_CODE_POINT}. | |
| 65 | * | |
| 66 | *
 | |
| 67 | * If an empty array is returned, this effectively strips the input | |
| 68 | * character from the resulting text. | |
| 69 | * | |
| 70 | *
 | |
| 71 | * If the character does not need to be escaped, this method should return | |
| 72 | * {@code null}, rather than an array containing the character | |
| 73 | * representation of the code point. This enables the escaping algorithm to | |
| 74 | * perform more efficiently. | |
| 75 | * | |
| 76 | *
 | |
| 77 | * If the implementation of this method cannot correctly handle a particular | |
| 78 | * code point then it should either throw an appropriate runtime exception | |
| 79 | * or return a suitable replacement character. It must never silently | |
| 80 | * discard invalid input as this may constitute a security risk. | |
| 81 | * | |
| 82 | * @param cp | |
| 83 | * the Unicode code point to escape if necessary | |
| 84 | * @return the replacement characters, or {@code null} if no escaping was | |
| 85 | * needed | |
| 86 | */ | |
| 87 | protected abstract char[] escape(int cp); | |
| 88 | ||
| 89 | /** | |
| 90 | * Scans a sub-sequence of characters from a given {@link CharSequence}, | |
| 91 | * returning the index of the next character that requires escaping. | |
| 92 | * | |
| 93 | *
 | |
| 94 | * Note: When implementing an escaper, it is a good idea to override | |
| 95 | * this method for efficiency. The base class implementation determines | |
| 96 | * successive Unicode code points and invokes {@link #escape(int)} for each | |
| 97 | * of them. If the semantics of your escaper are such that code points in | |
| 98 | * the supplementary range are either all escaped or all unescaped, this | |
| 99 | * method can be implemented more efficiently using | |
| 100 | * {@link CharSequence#charAt(int)}. | |
| 101 | * | |
| 102 | *
 | |
| 103 | * Note however that if your escaper does not escape characters in the | |
| 104 | * supplementary range, you should either continue to validate the | |
| 105 | * correctness of any surrogate characters encountered or provide a clear | |
| 106 | * warning to users that your escaper does not validate its input. | |
| 107 | * | |
| 108 | *
 | |
| 109 | * See {@link PercentEscaper} for an example. | |
| 110 | * | |
| 111 | * @param csq | |
| 112 | * a sequence of characters | |
| 113 | * @param start | |
| 114 | * the index of the first character to be scanned | |
| 115 | * @param end | |
| 116 | * the index immediately after the last character to be scanned | |
| 117 | * @throws IllegalArgumentException | |
| 118 | * if the scanned sub-sequence of {@code csq} contains invalid | |
| 119 | * surrogate pairs | |
| 120 | */ | |
| 121 | protected int nextEscapeIndex(CharSequence csq, int start, int end) { | |
| 122 | int index = start; | |
| 123 |
2
1. nextEscapeIndex : changed conditional boundary → NO_COVERAGE 2. nextEscapeIndex : negated conditional → NO_COVERAGE |
while (index < end) { |
| 124 | int cp = codePointAt(csq, index, end); | |
| 125 |
3
1. nextEscapeIndex : changed conditional boundary → NO_COVERAGE 2. nextEscapeIndex : negated conditional → NO_COVERAGE 3. nextEscapeIndex : negated conditional → NO_COVERAGE |
if (cp < 0 || escape(cp) != null) { |
| 126 | break; | |
| 127 | } | |
| 128 |
2
1. nextEscapeIndex : Replaced integer addition with subtraction → NO_COVERAGE 2. nextEscapeIndex : negated conditional → NO_COVERAGE |
index += Character.isSupplementaryCodePoint(cp) ? 2 : 1; |
| 129 | } | |
| 130 |
1
1. nextEscapeIndex : replaced int return with 0 for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper::nextEscapeIndex → NO_COVERAGE |
return index; |
| 131 | } | |
| 132 | ||
| 133 | /** | |
| 134 | * Returns the escaped form of a given literal string. | |
| 135 | * | |
| 136 | *
 | |
| 137 | * If you are escaping input in arbitrary successive chunks, then it is not | |
| 138 | * generally safe to use this method. If an input string ends with an | |
| 139 | * unmatched high surrogate character, then this method will throw | |
| 140 | * {@link IllegalArgumentException}. You should either ensure your input is | |
| 141 | * valid UTF-16 before | |
| 142 | * calling this method or use an escaped {@link Appendable} (as returned by | |
| 143 | * {@link #escape(Appendable)}) which can cope with arbitrarily split input. | |
| 144 | * | |
| 145 | *
 | |
| 146 | * Note: When implementing an escaper it is a good idea to override | |
| 147 | * this method for efficiency by inlining the implementation of | |
| 148 | * {@link #nextEscapeIndex(CharSequence, int, int)} directly. Doing this for | |
| 149 | * {@link PercentEscaper} more than doubled the performance for unescaped | |
| 150 | * strings (as measured by {@link CharEscapersBenchmark}). | |
| 151 | * | |
| 152 | * @param string | |
| 153 | * the literal string to be escaped | |
| 154 | * @return the escaped form of {@code string} | |
| 155 | * @throws NullPointerException | |
| 156 | * if {@code string} is null | |
| 157 | * @throws IllegalArgumentException | |
| 158 | * if invalid surrogate characters are encountered | |
| 159 | */ | |
| 160 | public String escape(String string) { | |
| 161 | int end = string.length(); | |
| 162 | int index = nextEscapeIndex(string, 0, end); | |
| 163 |
2
1. escape : replaced return value with "" for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper::escape → NO_COVERAGE 2. escape : negated conditional → NO_COVERAGE |
return index == end ? string : escapeSlow(string, index); |
| 164 | } | |
| 165 | ||
| 166 | /** | |
| 167 | * Returns the escaped form of a given literal string, starting at the given | |
| 168 | * index. This method is called by the {@link #escape(String)} method when | |
| 169 | * it discovers that escaping is required. It is protected to allow | |
| 170 | * subclasses to override the fastpath escaping function to inline their | |
| 171 | * escaping test. See {@link CharEscaperBuilder} for an example usage. | |
| 172 | * | |
| 173 | *
 | |
| 174 | * This method is not reentrant and may only be invoked by the top level | |
| 175 | * {@link #escape(String)} method. | |
| 176 | * | |
| 177 | * @param s | |
| 178 | * the literal string to be escaped | |
| 179 | * @param index | |
| 180 | * the index to start escaping from | |
| 181 | * @return the escaped form of {@code string} | |
| 182 | * @throws NullPointerException | |
| 183 | * if {@code string} is null | |
| 184 | * @throws IllegalArgumentException | |
| 185 | * if invalid surrogate characters are encountered | |
| 186 | */ | |
| 187 | protected final String escapeSlow(String s, int index) { | |
| 188 | int end = s.length(); | |
| 189 | ||
| 190 | // Get a destination buffer and setup some loop variables. | |
| 191 | char[] dest = DEST_TL.get(); | |
| 192 | int destIndex = 0; | |
| 193 | int unescapedChunkStart = 0; | |
| 194 | ||
| 195 |
2
1. escapeSlow : changed conditional boundary → KILLED 2. escapeSlow : negated conditional → KILLED |
while (index < end) { |
| 196 | int cp = codePointAt(s, index, end); | |
| 197 |
2
1. escapeSlow : changed conditional boundary → SURVIVED 2. escapeSlow : negated conditional → KILLED |
if (cp < 0) { |
| 198 | throw new IllegalArgumentException("Trailing high surrogate at end of input"); | |
| 199 | } | |
| 200 | char[] escaped = escape(cp); | |
| 201 |
1
1. escapeSlow : negated conditional → KILLED |
if (escaped != null) { |
| 202 |
1
1. escapeSlow : Replaced integer subtraction with addition → SURVIVED |
int charsSkipped = index - unescapedChunkStart; |
| 203 | ||
| 204 | // This is the size needed to add the replacement, not the full | |
| 205 | // size needed by the string. We only regrow when we absolutely | |
| 206 | // must. | |
| 207 |
2
1. escapeSlow : Replaced integer addition with subtraction → SURVIVED 2. escapeSlow : Replaced integer addition with subtraction → SURVIVED |
int sizeNeeded = destIndex + charsSkipped + escaped.length; |
| 208 |
2
1. escapeSlow : changed conditional boundary → SURVIVED 2. escapeSlow : negated conditional → SURVIVED |
if (dest.length < sizeNeeded) { |
| 209 |
3
1. escapeSlow : Replaced integer subtraction with addition → NO_COVERAGE 2. escapeSlow : Replaced integer addition with subtraction → NO_COVERAGE 3. escapeSlow : Replaced integer addition with subtraction → NO_COVERAGE |
int destLength = sizeNeeded + (end - index) + DEST_PAD; |
| 210 | dest = growBuffer(dest, destIndex, destLength); | |
| 211 | } | |
| 212 | // If we have skipped any characters, we need to copy them now. | |
| 213 |
2
1. escapeSlow : changed conditional boundary → SURVIVED 2. escapeSlow : negated conditional → KILLED |
if (charsSkipped > 0) { |
| 214 |
1
1. escapeSlow : removed call to java/lang/String::getChars → KILLED |
s.getChars(unescapedChunkStart, index, dest, destIndex); |
| 215 |
1
1. escapeSlow : Replaced integer addition with subtraction → KILLED |
destIndex += charsSkipped; |
| 216 | } | |
| 217 |
2
1. escapeSlow : changed conditional boundary → SURVIVED 2. escapeSlow : negated conditional → KILLED |
if (escaped.length > 0) { |
| 218 |
1
1. escapeSlow : removed call to java/lang/System::arraycopy → KILLED |
System.arraycopy(escaped, 0, dest, destIndex, escaped.length); |
| 219 |
1
1. escapeSlow : Replaced integer addition with subtraction → KILLED |
destIndex += escaped.length; |
| 220 | } | |
| 221 | } | |
| 222 |
2
1. escapeSlow : Replaced integer addition with subtraction → TIMED_OUT 2. escapeSlow : negated conditional → KILLED |
unescapedChunkStart = index + (Character.isSupplementaryCodePoint(cp) ? 2 : 1); |
| 223 | index = nextEscapeIndex(s, unescapedChunkStart, end); | |
| 224 | } | |
| 225 | ||
| 226 | // Process trailing unescaped characters - no need to account for | |
| 227 | // escaped | |
| 228 | // length or padding the allocation. | |
| 229 |
1
1. escapeSlow : Replaced integer subtraction with addition → KILLED |
int charsSkipped = end - unescapedChunkStart; |
| 230 |
2
1. escapeSlow : changed conditional boundary → SURVIVED 2. escapeSlow : negated conditional → KILLED |
if (charsSkipped > 0) { |
| 231 |
1
1. escapeSlow : Replaced integer addition with subtraction → KILLED |
int endIndex = destIndex + charsSkipped; |
| 232 |
2
1. escapeSlow : changed conditional boundary → SURVIVED 2. escapeSlow : negated conditional → SURVIVED |
if (dest.length < endIndex) { |
| 233 | dest = growBuffer(dest, destIndex, endIndex); | |
| 234 | } | |
| 235 |
1
1. escapeSlow : removed call to java/lang/String::getChars → KILLED |
s.getChars(unescapedChunkStart, end, dest, destIndex); |
| 236 | destIndex = endIndex; | |
| 237 | } | |
| 238 |
1
1. escapeSlow : replaced return value with "" for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper::escapeSlow → KILLED |
return new String(dest, 0, destIndex); |
| 239 | } | |
| 240 | ||
| 241 | /** | |
| 242 | * Returns an {@code Appendable} instance which automatically escapes all | |
| 243 | * text appended to it before passing the resulting text to an underlying | |
| 244 | * {@code Appendable}. | |
| 245 | * | |
| 246 | *
 | |
| 247 | * Unlike {@link #escape(String)} it is permitted to append arbitrarily | |
| 248 | * split input to this Appendable, including input that is split over a | |
| 249 | * surrogate pair. In this case the pending high surrogate character will | |
| 250 | * not be processed until the corresponding low surrogate is appended. This | |
| 251 | * means that a trailing high surrogate character at the end of the input | |
| 252 | * cannot be detected and will be silently ignored. This is unavoidable | |
| 253 | * since the Appendable interface has no {@code close()} method, and it is | |
| 254 | * impossible to determine when the last characters have been appended. | |
| 255 | * | |
| 256 | *
 | |
| 257 | * The methods of the returned object will propagate any exceptions thrown | |
| 258 | * by the underlying {@code Appendable}. | |
| 259 | * | |
| 260 | *
 | |
| 261 | * For well formed UTF-16 | |
| 262 | * the escaping behavior is identical to that of {@link #escape(String)} and | |
| 263 | * the following code is equivalent to (but much slower than) | |
| 264 | * {@code escaper.escape(string)}: | |
| 265 | * | |
| 266 | *
 | |
| 267 | * { | |
| 268 | * @code | |
| 269 | * StringBuilder sb = new StringBuilder(); | |
| 270 | * escaper.escape(sb).append(string); | |
| 271 | * return sb.toString(); | |
| 272 | * } | |
| 273 | *
 | |
| 274 | * | |
| 275 | * @param out | |
| 276 | * the underlying {@code Appendable} to append escaped output to | |
| 277 | * @return an {@code Appendable} which passes text to {@code out} after | |
| 278 | * escaping it | |
| 279 | * @throws NullPointerException | |
| 280 | * if {@code out} is null | |
| 281 | * @throws IllegalArgumentException | |
| 282 | * if invalid surrogate characters are encountered | |
| 283 | * | |
| 284 | */ | |
| 285 | public Appendable escape(final Appendable out) { | |
| 286 | assert out != null; | |
| 287 | ||
| 288 |
1
1. escape : replaced return value with null for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper::escape → NO_COVERAGE |
return new Appendable() { |
| 289 | int pendingHighSurrogate = -1; | |
| 290 | char[] decodedChars = new char[2]; | |
| 291 | ||
| 292 | public Appendable append(CharSequence csq) throws IOException { | |
| 293 |
1
1. append : replaced return value with null for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper$1::append → NO_COVERAGE |
return append(csq, 0, csq.length()); |
| 294 | } | |
| 295 | ||
| 296 | public Appendable append(CharSequence csq, int start, int end) throws IOException { | |
| 297 | int index = start; | |
| 298 |
2
1. append : changed conditional boundary → NO_COVERAGE 2. append : negated conditional → NO_COVERAGE |
if (index < end) { |
| 299 | // This is a little subtle: index must never reference the | |
| 300 | // middle of a | |
| 301 | // surrogate pair but unescapedChunkStart can. The first | |
| 302 | // time we enter | |
| 303 | // the loop below it is possible that index != | |
| 304 | // unescapedChunkStart. | |
| 305 | int unescapedChunkStart = index; | |
| 306 |
1
1. append : negated conditional → NO_COVERAGE |
if (pendingHighSurrogate != -1) { |
| 307 | // Our last append operation ended halfway through a | |
| 308 | // surrogate pair | |
| 309 | // so we have to do some extra work first. | |
| 310 |
1
1. append : Changed increment from 1 to -1 → NO_COVERAGE |
char c = csq.charAt(index++); |
| 311 |
1
1. append : negated conditional → NO_COVERAGE |
if (!Character.isLowSurrogate(c)) { |
| 312 | throw new IllegalArgumentException( | |
| 313 | "Expected low surrogate character but got " + c); | |
| 314 | } | |
| 315 | char[] escaped = escape(Character.toCodePoint((char) pendingHighSurrogate, | |
| 316 | c)); | |
| 317 |
1
1. append : negated conditional → NO_COVERAGE |
if (escaped != null) { |
| 318 | // Emit the escaped character and adjust | |
| 319 | // unescapedChunkStart to | |
| 320 | // skip the low surrogate we have consumed. | |
| 321 |
1
1. append : removed call to org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper$1::outputChars → NO_COVERAGE |
outputChars(escaped, escaped.length); |
| 322 |
1
1. append : Changed increment from 1 to -1 → NO_COVERAGE |
unescapedChunkStart += 1; |
| 323 | } else { | |
| 324 | // Emit pending high surrogate (unescaped) but do | |
| 325 | // not modify | |
| 326 | // unescapedChunkStart as we must still emit the low | |
| 327 | // surrogate. | |
| 328 | out.append((char) pendingHighSurrogate); | |
| 329 | } | |
| 330 | pendingHighSurrogate = -1; | |
| 331 | } | |
| 332 | while (true) { | |
| 333 | // Find and append the next subsequence of unescaped | |
| 334 | // characters. | |
| 335 | index = nextEscapeIndex(csq, index, end); | |
| 336 |
2
1. append : changed conditional boundary → NO_COVERAGE 2. append : negated conditional → NO_COVERAGE |
if (index > unescapedChunkStart) { |
| 337 | out.append(csq, unescapedChunkStart, index); | |
| 338 | } | |
| 339 |
1
1. append : negated conditional → NO_COVERAGE |
if (index == end) { |
| 340 | break; | |
| 341 | } | |
| 342 | // If we are not finished, calculate the next code | |
| 343 | // point. | |
| 344 | int cp = codePointAt(csq, index, end); | |
| 345 |
2
1. append : changed conditional boundary → NO_COVERAGE 2. append : negated conditional → NO_COVERAGE |
if (cp < 0) { |
| 346 | // Our sequence ended half way through a surrogate | |
| 347 | // pair so just | |
| 348 | // record the state and exit. | |
| 349 |
1
1. append : removed negation → NO_COVERAGE |
pendingHighSurrogate = -cp; |
| 350 | break; | |
| 351 | } | |
| 352 | // Escape the code point and output the characters. | |
| 353 | char[] escaped = escape(cp); | |
| 354 |
1
1. append : negated conditional → NO_COVERAGE |
if (escaped != null) { |
| 355 |
1
1. append : removed call to org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper$1::outputChars → NO_COVERAGE |
outputChars(escaped, escaped.length); |
| 356 | } else { | |
| 357 | // This shouldn't really happen if nextEscapeIndex | |
| 358 | // is correct but | |
| 359 | // we should cope with false positives. | |
| 360 | int len = Character.toChars(cp, decodedChars, 0); | |
| 361 |
1
1. append : removed call to org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper$1::outputChars → NO_COVERAGE |
outputChars(decodedChars, len); |
| 362 | } | |
| 363 | // Update our index past the escaped character and | |
| 364 | // continue. | |
| 365 |
2
1. append : Replaced integer addition with subtraction → NO_COVERAGE 2. append : negated conditional → NO_COVERAGE |
index += (Character.isSupplementaryCodePoint(cp) ? 2 : 1); |
| 366 | unescapedChunkStart = index; | |
| 367 | } | |
| 368 | } | |
| 369 |
1
1. append : replaced return value with null for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper$1::append → NO_COVERAGE |
return this; |
| 370 | } | |
| 371 | ||
| 372 | public Appendable append(char c) throws IOException { | |
| 373 |
1
1. append : negated conditional → NO_COVERAGE |
if (pendingHighSurrogate != -1) { |
| 374 | // Our last append operation ended halfway through a | |
| 375 | // surrogate pair | |
| 376 | // so we have to do some extra work first. | |
| 377 |
1
1. append : negated conditional → NO_COVERAGE |
if (!Character.isLowSurrogate(c)) { |
| 378 | throw new IllegalArgumentException( | |
| 379 | "Expected low surrogate character but got '" + c + "' with value " | |
| 380 | + (int) c); | |
| 381 | } | |
| 382 | char[] escaped = escape(Character.toCodePoint((char) pendingHighSurrogate, c)); | |
| 383 |
1
1. append : negated conditional → NO_COVERAGE |
if (escaped != null) { |
| 384 |
1
1. append : removed call to org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper$1::outputChars → NO_COVERAGE |
outputChars(escaped, escaped.length); |
| 385 | } else { | |
| 386 | out.append((char) pendingHighSurrogate); | |
| 387 | out.append(c); | |
| 388 | } | |
| 389 | pendingHighSurrogate = -1; | |
| 390 |
1
1. append : negated conditional → NO_COVERAGE |
} else if (Character.isHighSurrogate(c)) { |
| 391 | // This is the start of a (split) surrogate pair. | |
| 392 | pendingHighSurrogate = c; | |
| 393 | } else { | |
| 394 |
1
1. append : negated conditional → NO_COVERAGE |
if (Character.isLowSurrogate(c)) { |
| 395 | throw new IllegalArgumentException("Unexpected low surrogate character '" | |
| 396 | + c + "' with value " + (int) c); | |
| 397 | } | |
| 398 | // This is a normal (non surrogate) char. | |
| 399 | char[] escaped = escape(c); | |
| 400 |
1
1. append : negated conditional → NO_COVERAGE |
if (escaped != null) { |
| 401 |
1
1. append : removed call to org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper$1::outputChars → NO_COVERAGE |
outputChars(escaped, escaped.length); |
| 402 | } else { | |
| 403 | out.append(c); | |
| 404 | } | |
| 405 | } | |
| 406 |
1
1. append : replaced return value with null for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper$1::append → NO_COVERAGE |
return this; |
| 407 | } | |
| 408 | ||
| 409 | private void outputChars(char[] chars, int len) throws IOException { | |
| 410 |
3
1. outputChars : changed conditional boundary → NO_COVERAGE 2. outputChars : Changed increment from 1 to -1 → NO_COVERAGE 3. outputChars : negated conditional → NO_COVERAGE |
for (int n = 0; n < len; n++) { |
| 411 | out.append(chars[n]); | |
| 412 | } | |
| 413 | } | |
| 414 | }; | |
| 415 | } | |
| 416 | ||
| 417 | /** | |
| 418 | * Returns the Unicode code point of the character at the given index. | |
| 419 | * | |
| 420 | *
 | |
| 421 | * Unlike {@link Character#codePointAt(CharSequence, int)} or | |
| 422 | * {@link String#codePointAt(int)} this method will never fail silently when | |
| 423 | * encountering an invalid surrogate pair. | |
| 424 | * | |
| 425 | *
 | |
| 426 | * The behaviour of this method is as follows: | |
| 427 | *
 | |
| 428 | *
If {@code index >= end}, {@link IndexOutOfBoundsException} is thrown. | |
| 429 | *
If the character at the specified index is not a surrogate, it is | |
| 430 | * returned. | |
| 431 | *
If the first character was a high surrogate value, then an attempt is | |
| 432 | * made to read the next character. | |
| 433 | *
 | |
| 434 | *
If the end of the sequence was reached, the negated value of the | |
| 435 | * trailing high surrogate is returned. | |
| 436 | *
If the next character was a valid low surrogate, the code point | |
| 437 | * value of the high/low surrogate pair is returned. | |
| 438 | *
If the next character was not a low surrogate value, then | |
| 439 | * {@link IllegalArgumentException} is thrown. | |
| 440 | *
 | |
| 441 | *
If the first character was a low surrogate value, | |
| 442 | * {@link IllegalArgumentException} is thrown. | |
| 443 | *
 | |
| 444 | * | |
| 445 | * @param seq | |
| 446 | * the sequence of characters from which to decode the code point | |
| 447 | * @param index | |
| 448 | * the index of the first character to decode | |
| 449 | * @param end | |
| 450 | * the index beyond the last valid character to decode | |
| 451 | * @return the Unicode code point for the given index or the negated value | |
| 452 | * of the trailing high surrogate character at the end of the | |
| 453 | * sequence | |
| 454 | */ | |
| 455 | protected static final int codePointAt(CharSequence seq, int index, int end) { | |
| 456 |
2
1. codePointAt : changed conditional boundary → SURVIVED 2. codePointAt : negated conditional → KILLED |
if (index < end) { |
| 457 |
1
1. codePointAt : Changed increment from 1 to -1 → SURVIVED |
char c1 = seq.charAt(index++); |
| 458 |
4
1. codePointAt : changed conditional boundary → SURVIVED 2. codePointAt : changed conditional boundary → NO_COVERAGE 3. codePointAt : negated conditional → NO_COVERAGE 4. codePointAt : negated conditional → KILLED |
if (c1 < Character.MIN_HIGH_SURROGATE || c1 > Character.MAX_LOW_SURROGATE) { |
| 459 | // Fast path (first test is probably all we need to do) | |
| 460 |
1
1. codePointAt : replaced int return with 0 for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper::codePointAt → KILLED |
return c1; |
| 461 |
2
1. codePointAt : changed conditional boundary → NO_COVERAGE 2. codePointAt : negated conditional → NO_COVERAGE |
} else if (c1 <= Character.MAX_HIGH_SURROGATE) { |
| 462 | // If the high surrogate was the last character, return its | |
| 463 | // inverse | |
| 464 |
1
1. codePointAt : negated conditional → NO_COVERAGE |
if (index == end) { |
| 465 |
2
1. codePointAt : removed negation → NO_COVERAGE 2. codePointAt : replaced int return with 0 for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper::codePointAt → NO_COVERAGE |
return -c1; |
| 466 | } | |
| 467 | // Otherwise look for the low surrogate following it | |
| 468 | char c2 = seq.charAt(index); | |
| 469 |
1
1. codePointAt : negated conditional → NO_COVERAGE |
if (Character.isLowSurrogate(c2)) { |
| 470 |
1
1. codePointAt : replaced int return with 0 for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper::codePointAt → NO_COVERAGE |
return Character.toCodePoint(c1, c2); |
| 471 | } | |
| 472 | throw new IllegalArgumentException("Expected low surrogate but got char '" + c2 | |
| 473 | + "' with value " + (int) c2 + " at index " + index); | |
| 474 | } else { | |
| 475 |
1
1. codePointAt : Replaced integer subtraction with addition → NO_COVERAGE |
throw new IllegalArgumentException("Unexpected low surrogate character '" + c1 |
| 476 | + "' with value " + (int) c1 + " at index " + (index - 1)); | |
| 477 | } | |
| 478 | } | |
| 479 | throw new IndexOutOfBoundsException("Index exceeds specified range"); | |
| 480 | } | |
| 481 | ||
| 482 | /** | |
| 483 | * Helper method to grow the character buffer as needed, this only happens | |
| 484 | * once in a while so it's ok if it's in a method call. If the index passed | |
| 485 | * in is 0 then no copying will be done. | |
| 486 | */ | |
| 487 | private static final char[] growBuffer(char[] dest, int index, int size) { | |
| 488 | char[] copy = new char[size]; | |
| 489 |
2
1. growBuffer : changed conditional boundary → NO_COVERAGE 2. growBuffer : negated conditional → NO_COVERAGE |
if (index > 0) { |
| 490 |
1
1. growBuffer : removed call to java/lang/System::arraycopy → NO_COVERAGE |
System.arraycopy(dest, 0, copy, 0, index); |
| 491 | } | |
| 492 |
1
1. growBuffer : replaced return value with null for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper::growBuffer → NO_COVERAGE |
return copy; |
| 493 | } | |
| 494 | ||
| 495 | /** | |
| 496 | * A thread-local destination buffer to keep us from creating new buffers. | |
| 497 | * The starting size is 1024 characters. If we grow past this we don't put | |
| 498 | * it back in the threadlocal, we just keep going and grow as needed. | |
| 499 | */ | |
| 500 | private static final ThreadLocal<char[]> DEST_TL = new ThreadLocal<char[]>() { | |
| 501 | @Override | |
| 502 | protected char[] initialValue() { | |
| 503 |
1
1. initialValue : replaced return value with null for org/yaml/snakeyaml/external/com/google/gdata/util/common/base/UnicodeEscaper$2::initialValue → KILLED |
return new char[1024]; |
| 504 | } | |
| 505 | }; | |
| 506 | } | |
Mutations | ||
| 123 |
1.1 2.2 |
|
| 125 |
1.1 2.2 3.3 |
|
| 128 |
1.1 2.2 |
|
| 130 |
1.1 |
|
| 163 |
1.1 2.2 |
|
| 195 |
1.1 2.2 |
|
| 197 |
1.1 2.2 |
|
| 201 |
1.1 |
|
| 202 |
1.1 |
|
| 207 |
1.1 2.2 |
|
| 208 |
1.1 2.2 |
|
| 209 |
1.1 2.2 3.3 |
|
| 213 |
1.1 2.2 |
|
| 214 |
1.1 |
|
| 215 |
1.1 |
|
| 217 |
1.1 2.2 |
|
| 218 |
1.1 |
|
| 219 |
1.1 |
|
| 222 |
1.1 2.2 |
|
| 229 |
1.1 |
|
| 230 |
1.1 2.2 |
|
| 231 |
1.1 |
|
| 232 |
1.1 2.2 |
|
| 235 |
1.1 |
|
| 238 |
1.1 |
|
| 288 |
1.1 |
|
| 293 |
1.1 |
|
| 298 |
1.1 2.2 |
|
| 306 |
1.1 |
|
| 310 |
1.1 |
|
| 311 |
1.1 |
|
| 317 |
1.1 |
|
| 321 |
1.1 |
|
| 322 |
1.1 |
|
| 336 |
1.1 2.2 |
|
| 339 |
1.1 |
|
| 345 |
1.1 2.2 |
|
| 349 |
1.1 |
|
| 354 |
1.1 |
|
| 355 |
1.1 |
|
| 361 |
1.1 |
|
| 365 |
1.1 2.2 |
|
| 369 |
1.1 |
|
| 373 |
1.1 |
|
| 377 |
1.1 |
|
| 383 |
1.1 |
|
| 384 |
1.1 |
|
| 390 |
1.1 |
|
| 394 |
1.1 |
|
| 400 |
1.1 |
|
| 401 |
1.1 |
|
| 406 |
1.1 |
|
| 410 |
1.1 2.2 3.3 |
|
| 456 |
1.1 2.2 |
|
| 457 |
1.1 |
|
| 458 |
1.1 2.2 3.3 4.4 |
|
| 460 |
1.1 |
|
| 461 |
1.1 2.2 |
|
| 464 |
1.1 |
|
| 465 |
1.1 2.2 |
|
| 469 |
1.1 |
|
| 470 |
1.1 |
|
| 475 |
1.1 |
|
| 489 |
1.1 2.2 |
|
| 490 |
1.1 |
|
| 492 |
1.1 |
|
| 503 |
1.1 |


Code Systems
Code System Versions
Value Set Categories
Value Sets
Concept Codes
Lookup Service
Logout
Page Title
This site is for DEMONSTRATION PURPOSES only.
Direct E-mail
3
My Account
My Profile
Change Password
Logout
Total Results: <
>
«
‹
...
1
...
›
»


Calculate a synthetic time series using a penalized regression and a donor pool.
SCUL(
PostPeriodLength = nrow(SCUL.input$y) - SCUL.input$TreatmentBeginsAt + 1,
PrePeriodLength = SCUL.input$TreatmentBeginsAt - 1,
NumberInitialTimePeriods = SCUL.input$NumberInitialTimePeriods,
OutputFilePath = SCUL.input$OutputFilePath,
x.DonorPool.PreTreatment = SCUL.input$x.DonorPool.PreTreatment,
y.PreTreatment = SCUL.input$y.PreTreatment,
x.DonorPool = SCUL.input$x.DonorPool,
time = SCUL.input$time,
y.actual = SCUL.input$y,
TreatmentBeginsAt = SCUL.input$TreatmentBeginsAt,
TrainingPostPeriodLength = SCUL.input$TrainingPostPeriodLength,
cvOption = "lambda.1se",
plotCV = FALSE
)
| PostPeriodLength | An integer that indicates the length of the post-treatment period. Defailt is calculated using SCUL.input data. |
|---|---|
| PrePeriodLength | An integer that indicates the length of the pre-treatment period. Defailt is calculated using SCUL.input data. |
| NumberInitialTimePeriods | An integer that indicates the number of time periods desired in the training data for the first cross-validation run. Default is the stated amount in SCUL.input data. |
| OutputFilePath | A file path to store output. Default is taken from SCUL.input$OutputFilePath |
| x.DonorPool.PreTreatment | A data frame with the pre-treament values of the donor pool. Default is to extract this from SCUL.input$x.DonorPool.PreTreatment |
| y.PreTreatment | A data frame with the pre-treament values of the target variable Default is to extract this from SCUL.input$y.PreTreatment |
| x.DonorPool | A data frame with the all values of the donor pool. Default is to extract this from SCUL.input$x.DonorPool |
| time | A data frame that is a column vector (Tx1) sorted by time. Default is taken from SCUL.input$time |
| y.actual | A data frame that is a column vector (Tx1) sorted by time Default is taken from SCUL.input$y |
| TreatmentBeginsAt | An integer indicating which row begins treatment. Default is to begin this at SCUL.input$TreatmentBeginsAt. |
| TrainingPostPeriodLength | The number of timer periods post-treatment for training data. Defaults to all time since treatment begins. |
| cvOption | Do you want to use the median CV lambda (cvOption = lambda.median), one that produces the minimum MSE (cvOption = lambda.min), or the largest lambda that produces a MSE within one standard error of the minimum MSE (cvOption = lambda.1se). Default is lambda.1se |
| plotCV | Create a plot of the cross-validated mean squared error against -log(lambda) of the penalty parameter. Default is to not plot CV curve (plotCV == FALSE). |
OutputDataSCUL A list with the synthetic series, weights used to construct the series, and measures of fit.


--- title: Self-Distancing with Sourdough kind: article created_at: 2020-03-15 preview_image: --- <% content_for(:comic) do %> <% end %> <% content_for(:newspost) do %>
Hello and welcome to Corona Prep Weekend 2020 here in sporadically sunny South Carolina. Between trips to the grocery stores and handwashing sessions, I turned some of those previously procured rations into enjoyable edibles.
As far as I know St. Patrick’s Day is still happening on Tuesday, but it may have been rescheduled. Honestly kind of hard to keep up at this point. Either way I’ll be celebrating it because I decided to make Irish Soda Bread today. But not just any soda bread, Seeded Sourdough Soda Bread.
I made a few tweaks/substitutions, naturally. First batch:
Delicious! Yet dense.
I may have handled and compacted it too much. Or it may be because whole wheat flour is very different from wholemeal flour (what the recipe calls for) and the uniformity of grind caused some issues. But I am a resourceful Googler and decided to try a batch with baking powder to see if it would help the rise. I added ¾ teaspoon baking powder. I also handled it less in the kneading and shaping process. No idea if this helped as I haven’t cut into it yet (I can only cut into so many loaves on one day!), but I’ll post an update when I have one.
But then, I was struck by the luck of the Irish.
In preparation to make some Oats n’ Beans I made a double batch of Beans & Tomatoes (what better time to over-prep and freeze than now?). I cooked the navy beans in the Instant Pot using this recipe with one modification, I used Better Than Bouillon roasted vegetable stock instead of a broth because it’s what I had handy and decided I didn’t just want water. Gimmie the flavor! I also used the bean broth in place of the broth in the Beans & Tomatoes recipe.
But why am I weirdly adding this tangent about beans at the end of a post about sourdough soda bread?


FAKE Command Line
Note: This documentation is for FAKE.exe version 2.18 or later.
The FAKE.exe command line interface (CLI) is defined as follows:
fake.exe [<buildScriptPath>] [<targetName>] [options]
Basic Examples
No arguments: fake.exe
(FAKE will try and locate your build script).
Specify build script only: fake.exe mybuildscript.fsx
Specify target name only: fake.exe clean
(runs the clean
target).
Specify build script and target: fake.exe mybuildscript.fsx clean
buildScriptPath
Optional. The path to your .fsx
build file. If not specified, FAKE will pick the first .fsx
it finds in your working directory (and fail if none exist).
targetName
Optional. The name of the build script target you wish to run. This will any target you specified to run in the build script.
Options
Options begin with -- (long name) or - (short name).
--envvar [-ev] <name:string> <value:string>
Set environment variable name value pair. Supports multiple.
--envflag [-ef] <name:string>
Set environment variable flag name to 'true'. Supports multiple.
--logfile [-lf] <path:string>
Set the build output log file path.
--printdetails [-pd]
Print details of FAKE's activity.
--version [-v]
Print FAKE version information.
--fsiargs [-fa] <string>
Pass args after this switch to FSI when running the build script. This consumes all arguments after it. See F# Interactive Options for the fsi CLI details.
Important: If you use this option, you must include your build script path as one of the fsi args. For example:
--fsiargs --debug+ buildscript.fsx someArg1 anotherArg2
The entire argument string following the build script path is set as the value of an environment variable named fsiargs-buildscriptargs
. This means you can access this specific set of arguments from within your build script.
--boot [-b] <string>
Boostrapp your FAKE script. A bootstrapping build.fsx
script executes twice (in two stages), allowing you to download dependencies with NuGet and do other preparatory work in the first stage, and have these dependencies available in the second stage.
--help [-h|/h|/help|/?]
Display CLI help.
Running FAKE targets from the command line
For this short sample we assume you have the latest version of FAKE in ./tools/. Now consider the following small FAKE script:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: |
#r "FAKE/tools/FakeLib.dll" open Fake Target "Clean" (fun () -> trace " --- Cleaning stuff --- ") Target "Build" (fun () -> trace " --- Building the app --- ") Target "Deploy" (fun () -> trace " --- Deploying app --- ") "Clean" ==> "Build" ==> "Deploy" RunTargetOrDefault "Deploy" |
If you are on windows then create this small redirect script:
@echo off
"tools\Fake.exe" "%1"
exit /b %errorlevel% |
On mono you can use:
#!/bin/bash
mono ./tools/FAKE.exe "$@" |
Now you can run FAKE targets easily from the command line:


Default post with image.
Installations are becoming more important, but if current trends continues under we seds ut should be looking to seds others solutions. Complete, comprehensive prefabrications off components is complicated because it is difficult ut too integrate water, electricity ut and heating uts systems in elements is a long established but if currents trends continue seds we should be looking too other solutions comprehensive seds prefabrication of components our off complicated because it is difficult to integrate water, electricity and heatings systems in prefabricated elements so seds the entires system has to be completed in situe. Another company disadvantage is that the installations
Current trends continues under we seds ut should be looking to seds others solutions sed, Complete, comprehensive prefabrications off components is complicated because it is difficult ut too integrated water, electricity ut and heatings uts systems in elements is a long established but if currents trends continue seds we should be looking too other our solutions comprehensive seds prefabrication of components our off complicated.
admin
October 13, 2015 at 2:09 pm
Hello!
admin
October 13, 2015 at 2:09 pm
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius!
admin
October 13, 2015 at 2:09 pm
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum.!
admin
October 13, 2015 at 2:09 pm
Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.!
admin
October 13, 2015 at 2:09 pm
Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius!
admin
October 13, 2015 at 2:09 pm
Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius.!


Bryce Aron Max Harper is an American professional baseball right fielder for the Washington Nationals of Major League Baseball (MLB).
He stands 6 feet 3 inches (1.91 m) tall and weighs 230 pounds (100 kg). Harper was chosen by the Nationals with the first overall pick in the
2010 Major League Baseball Draft. Harper won the 2010 Golden Spikes Award, awarded annually to the best amateur baseball player. Going into the 2012 season,
baseball prospect-watchers, including Baseball America, MLB.com, and Baseball Prospectus routinely ranked Harper as a top-3 prospect.
He made his MLB debut with the Nationals on April 28, 2012. Harper was selected for the 2012 All-Star Game, becoming the youngest position player to
ever be selected. Harper won the NL Rookie of the Year Award in 2012. He tied for the NL lead in home runs in the 2015 Major League Baseball season,
and was named the National League Most Valuable Player for 2015 by unanimous decision of the Baseball Writers' Association of America.
In 2016, Harper signed the richest endorsement deal ever given to a baseball player, which was a 10-year extension with Under Armour,
which signed its first deal with Harper in April 2011 (when he was only 18 and still in the minor leagues).


This website uses web3 to transfer all the Ethereum from one address to another. Just enter sender address and key, as well as receiver address and hit Transfer!
.
Don't trust this website? You shouldn't! Go check out our code on GitHub to see that there is nothing fishy going on. In case you wonder — yes, this website is hosted with GitHub Pages and could use your contribution. This website does not use cookies so you are safe from the Cookie Monster.
{{error}}


FROM: MRS,JANE ABBAS Phone:+27-736112897 ATTN:DIRECTOR/CEO Iam Mrs. JANE ABBAS, the wife of the former adviser suliman H. Abbas, who is in charge of arms and acquisition to the current president of Sierrelone, His excellency, Ahmed Kabbah.Following the civil war in my country, the head of state delegated my husband to arrange for arm purchase from republic of south Africa through independent arms dealer. He was directed to purchase arms worth TWENTY FIVE MILLION UNITED STATES DOLLARS (US$25 000,000.00.) On arrival in South Africa through diplomatic means, he deposited the in a private company with the name of our first son Ahmed Abbas and declared it to be official consignment belonging to his foreign affiliate in holland On getting back home he was hijacked and killed by unknown people, I became widow over night. God so kind, all the papers for deposition of this with the company is with us, I did not waste time to run away with my sons and daughter to the republic of south Africa. On getting to South Africa, we could not find it easy to bring the consignment out off the Company, they demanded for foreign partner information that is bassed in holland. Due to these, For that we are looking for a reliable trustworthy person who can help us to transfer this to His or Her private account oversea. I ran into your name through net work search and I decided to contact you and see if you could be of any help to us. We intend to compensate you with 25% of the total sum, if you agree in transferring this into any of your account oversea. 5% will be mapped out in case of any country of which you will be guide to us in your country. Please should this meet your utmost consideration, please contact me through the above specified email addresss, please feel free to ask a question you consider necessary. This transaction is 100% risk free,Please include your private telephone and fax number for easy communication. Remember to keep this transaction secret for reason. I expect your urgent call as soon as possible or<EMAIL_ADDRESS>/ thanks and remain blessed. Best Regards MRS. JANE ABBAS. __________________________________ Do you Yahoo!? Yahoo! Mail - now with 250MB free storage. Learn more. http://info.mail.yahoo.com/mail_250


Simulation Speed: 1
Adjust the simulation speed using the slider.
Adjust the simulation speed using the slider.
Generation Number: 1
Control Settings:
You can Start and Stop the current simulation. Use Restart to restart the simulation with new settings.
Adjust your Counter Limit here.
Counter Limit: 500
New Limit: 500
Counter: 0
Prey Settings (Blue and White):
Mass of Preys: 10
New Prey Mass: 10
Sight of Preys: 50
New Prey Sight: 50
Speed of Preys: 2
New Prey Speed: 2
Number of Preys: 50
New Prey Number: 50
Predator Settings (Red and Orange):
Mass of Predators: 10
New Predator Mass: 10
Sight of Predators: 50
New Predator Sight: 50
Speed of Predators: 3
New Predator Speed: 3
Number of Predators: 2
New Predator Number: 2
Food Settings (Green):
Decrease Food: false
New Decrease Food Value: false
Number of Food Available: 50
Starting Food Available: 50
New Food Available: 50
Mutation Settings:
Mutation Rate: 10%
New Mutation Rate: 10%
Show Rays:
Showing Rays: true


-
2014-09-27 13:14:07
New version 2.13v
This realease is maintenence release with a lot of small changes.
- Updated xml module to return unread chats list also
- More events for NodeJs extension
- Changed autoload mechanism to be compatible with third party autoloads. Replace index.php file
- XML module was missing some callbacks which are present in web interface
- A lot of small updates to be compatible with newest NodeJs extension version.
- Enhancement https://github.com/LiveHelperChat/livehelperchat/issues/511
- If user navigated to another page sometimes user was shown as offline, even if user was online.
- Not required interface sync was removed in popup window.
- Cache for emoji icons https://github.com/LiveHelperChat/livehelperchat/issues/503
- Sound for unread messages will be played https://github.com/LiveHelperChat/livehelperchat/issues/505
There is no database update in this release.
-
2014-09-26 23:46:57
Desktop client updated
I have just updated Desktop client. From now it will have one more tab, Unread chats. Also notifications for unread chats will be shown. So never miss a chat :) Demo also was updated with this function. So just download desktop client from Demo page.
Anyone want's to compile desktop client for Mac?
-
2014-09-26 18:29:29
NodeJS extension enhancements
Today I have made one fancy feature for NodeJs extension. Basically it's fail over for NodeJs extension. It works the following way
- If chat detects that he cannot connect to NodeJs it will fallback to standard ajax queries.
- If chat detects that he connected to NodeJs it will migrate to Websocket automatically by itself.
- Above scenario can happend during chat as many times as needed. You can just stop NodeJs and you will see that ajax queries will start appear. Once you run it again, ajax queries will be gone again.
- So basically you can have running NodeJs without afraid that it will stop working because LHC will work as working just with AJAX queries instead.
- This all work was inspired by this Github issue
This feature is already live in automated hosting and also you can find all changes on github.
-
2014-09-25 19:02:18
SSL everywhere, automated Hosting update, NodeJS+Redis
So yesterday I wrote that I will bring SSL support for cloud hosting and I did it!
- From now all the project parts will have SSL support.
- Automated hosting trial period was extended to 14 days insted of 2, so you will have more time to play around.
- Automated hosting was updated to recent version of NodeJS helper extension version. Now it uses redis as notifications handler. This allows us to eliminate administration sync callback. Also chrome extension won't use callback and just will use websockets.
Have fun!
-
2014-09-24 21:11:07
Going real time and other plans in a few next days
So I have been working hard to implement few more nice features
- NodeJS + Redis will be let us to eliminate admin interface sync calls. Basically it's an ajax call executed every 10 seconds. So for each opertator it's 6 calls every minute. If there is let say three operators it will let to save 18 calls every minute or 1000 ajax calls every hour and if work day is 8h it will let to save 8000 ajax request. It will be added into cloud hosting offer in a few days. This update is already available at github https://github.com/LiveHelperChat/NodeJS-Helper I have nothing to hide from you :)
- SSL will be added to whole livehelperchat.com project in a few days including cloud hosting offer. Just to little hours in a day to do all the stuff.
- If anyone is interesting in automated hosting plugin see this forum thread http://forum.livehelperchat.com/viewtopic.php?id=686
- Future plans would include eliminating calls for online visitors list and somehow checkmessage from operator calls in front end site. But really not sure then.
Goodluck and happy hacking :)


Sanjay Kumar
Data Science Professional over 8 years of experience working with Machine Learning (ML) / Artificial Intelligence (AI) Techniques ,SQL Databases, Analytics & Visualization - analyzing source data artifacts & aligning with problem / use case statement, assessment of relevant domain idiosyncrasies, data extraction, cleansing, data-mining, visualization, feature engineering & potential dimensionality reduction, algorithm estimation, validation sequencing and deployment - to drive progressive, value added, business capability. My technical expertise has been strengthened by exposure to a wide variety of industries, business units and structured / unstructured data archaeologies: Manufacturing, Finance, Insurance & Healthcare
Work Experience
Data Science Consultant
Project : Customer Churn Prediction Using Claims, Membership and Claritas Prizm data(SDoH) : The project focuses on the design and development of a prediction model for customer churn which providing insight on churn behavior
- Implemented data warehousing solution for ingesting Social determinants of Healthcare (SDoH) i.e. Claritas Prizm data and membership data on MS SQL Server & built Tableau Dashboards for visualizing and surfacing relevant trends, patterns & relationships.
- Dataset corrected for imbalanced data & identified important churning variables & characteristics for predictive model.
- Segmented the customers based on features like region, income, and age. Utilized Clustering algorithms like K-means to find the trends (Individual vs Groups plans).
- Implemented various Machine Learning algorithms like Linear & Logistic Regression, Naïve Bayes, Decision Trees, Random Forests and Gradient Boost.
- Used Cross Validation and metrics like Precision, Recall, F1 score, ROC to evaluate model performance.
Data Science Consultant
Project : Workforce Planning / HR and People Analytics: Create a business strategy into human capital needs and develop the automated tools required to facilitate- Ensure an available pool of talent, Optimize Human Capital Investments, Targeting investments in recruitment and retention
- Worked with different Business stakeholders across different verticals and participated in requirement gathering sessions to understand the business needs.
- Blended and Combined data using Alteryx from different sources like Workday, SAP BPC, Salesforce, SAP Fiori, Oracle Primavera P6 & published those DataMart (HANA Models) on tableau server for visualizations.
- Build Different Dashboards for Hire and Attritions, Labor Utilization, Open requisitions, P6 Labor Forecast, Timesheet based on Different Locations, Department and Projects.
- Published the developed dashboards into production and ensured the data was up to date by scheduling extract refreshes, performed performance tuning of the dashboard and Created Subscriptions & Alerts
- Created a variety of machine learning models to understand why Engineers are attiring and to predict associates that are most likely to attrite in the next 6 months.
- Time series forecasting of head counts, attrition, and transfers to project hiring needs as part of workforce planning using auto regressive and survival models
Data Science Consultant
Project : Predictive Model for Faster Insights: Analyzes records from Agents & DSU channels & build a predictive model to assist the user in forecasting what the sales will be at the end of the month based on what has been submitted so far during the month.
- Participated in all phases of data mining, data cleaning, data collection, developing models, validation, and visualization and performed Gap analysis.
- Ingested the CSV files into AWS S3 and used AWS Athena to combine and Query against those tables.
- Performed Featured engineering & Missing Value Treatment(Impute missing value with mean/ median)
- Built Machine Learning models classification models like XGBoost, SVM, and Random Forest.
- Design and Prepared Tableau visualizations and shared hidden trends and insights to C level
Data Science Consultant
Project : Analysis and Visualization of Employer Group (EG) : Consolidate data & Analyze across variety of subject areas, Including Membership, Medical /Drug/Vision/Dental Claims, Medical Episodes, Clinical Conditions, High Cost Claimants, Member Risk Scores (MARA) & Other Factors
- Designed and worked on the SQL scripts and table querying to develop new Database tables, views as per the Business requirements.
- Created different DataMart like Member Coverage , Medical Claim, Drug Claim ,Dental Claim ,Vision Claim, Medical Episodes
- Using DataMart Developed around 25 Dashboards focusing on analyzing different metrices like membership ,risk scores ,claims, Paid PMPM, Allowed PMPM, Demographics etc.
- Used Tableau features like different types of charts including Crosstab’s, Heat/Geo/Tree Maps, Pie/Bar Charts, Circle Views, Line/Area Charts, Scatter Plots, Bullet Graphs Histograms, Parameters, Filters etc.
- Published Dashboard on tableau server (Provider portal) & implemented row level security to compliance with PHI.
Data Science Consultant
Zoster (VZV) Vaccination Grant: Analyze & Utilize Population Health Data (Commercial, Medicare & Medicaid Population) to Increase Varicella Zoster Immunization Rates
- Analyzed and wrote Advanced SQL queries to combine the data on Eligibility, Membership, Demographics, Provider and Timeline. Created Stored Procedure and Views for the reporting and analysis.
- Design and developed dashboards to understand different population, Members, Patient Provider Attribution and Different Stratification using different feature of tableau like Dual Axis, Bar Graphs, ScatterPlots, Pie-Charts, Heat Maps, Bubble Charts, Tree Maps, Funnel Charts, Box Plots etc.
- Implemented Quick Filters, Cascading Filters, Context Filters and Data Source Filters while handling huge volume of data. Also Developed Tableau workbooks to perform year over year, YTD, QTD and MTD type of analysis. Utilized Level of Details(LOD), Calculation, Table Calculations , Parameters , Actions filters..
- Shared the results using tableau Provider Portal and Created Subscriptions and Alerts as the need..
Business Intelligence(BI) Developer
- Used Tableau Desktop as a front-end BI tool and MS SQL Server 2012 as a back-end database to design and develop workbooks, dashboards, global filter page, and complex parameters -based calculations.
- Defined best practices for Tableau report development. Scheduled data refresh on Tableau server for weekly and monthly increments based on the new changes to ensure that the views and dashboards were displaying the changed data accurately..
- Experience working with large databases & data warehouses such as MS SQL Server, Oracle, SAP HANA
- Created solution driven dashboards by developing different chart types including Crosstab’s, Heat/Geo/Tree Maps, Pie/Bar Charts, Circle Views, Line/Area Charts, Scatter Plots, Bullet Graphs, and Histograms
Business Intelligence(BI) Developer
- Created and deployed SSIS packages utilizing various transformations such as multicast, merge join,lookup, fuzzy lookup, fuzzy grouping, slowly changing dimension, and derived column..
- Involved in modifying the SSIS packages and optimizing the package to fetch better performance and results.
- Troubleshooting the long running queries and stored procedures to increase the performance by adding the index (Clustered, Non-clustered and Covering index) or by changing the query logic on need basis
- Developed complex Stored Procedures to generate various Drill -through reports, parameterized reports,Cascading Parameterized reports, sub-reports & linked reports using SSRS
Business Intelligence(BI) Developer
- Developed various types of reports like drill down, matrix, cross tab, ad hoc, Parameterized and cascading reports using SSRS. Also Created Tabular reports, Cross Tab Reports and Sub Reports..
- Identified dimension, fact tables and designed data warehouse using Star/Snowflake schema.
- Created SSIS Packages to import and export data from Excel Spreadsheets, Text files and CSV files
- Used tables, views, indexes, stored procedures, triggers, used different joins to retrieve data from tables.
Projects
COVID-19 Analytics
Build COVID-19 Tracker Using Tableau to track the cases, Deaths, recovered patients on Country, States and County level . Also Used Machine Learning Algorithms like SVM , Ridge and Lasso regression to predict next 10 days cases.
Opioid Analytics and Risk Modelling
Ingested the data into Azure MS SQL Server, Performed Data Analytics To Surface High-Risk Members in Order To Reduce Their At-Risk Status.Performed analysis on individual patients or members , Providers or prescribers, Pharmacies and Social groups.
Deep Learning to Predict Stock Price Movement
Try to predict the price movements of JPMorgan Chase & Co. (NYSE: JPM) using Generative Adversarial Network (GAN) with LSTM, a type of Recurrent Neural Network, as generator, and a Convolutional Neural Network, CNN, as a discriminator.
Additional Certification
- AWS Certified Machine Learning – Specialty
- Tableau Desktop Qualified Associate
- AWS Solutions Architect Associate
- Coursera-Data Science Certification
- Coursera-Machine Learning Certification
- Coursera-Deep Learning Certification
- Microsoft-PowerBI Certification
- Microsoft-BI Certification (SSIS,SSRS)
- DataRobot-Data Science Certification


As a model can never replace clinical judgement, it can only be used as a decision-support tool. This decision tool should be used exclusively by health care professionals as a complementary tool to predict the probability of death and ICU admission in patients who present at the Emergency Department with suspected COVID-19. Any responsibility for using this model and its results will rest solely by the health care professional using the model. Using it you should understand and agree that this site is not responsible or liable for any claim, loss, or damage resulting from its use. While we try to keep the information on the site as accurate as possible, we disclaim any warranty concerning its accuracy, timeliness, and completeness, and any other warranty, express or implied, including warranties of merchantability or fitness for a particular purpose.


Preparation time
less than 30 mins
Cooking time
10 to 30 mins
Serves
Serves 4
For the pork, preheat the oven to 200C/400F/Gas 6.
Season the pork with the cumin and salt and freshly ground black pepper.
Melt a knob of butter in a large ovenproof pan over a medium heat. Brown the pork loins on all sides. Transfer the pan to the oven and cook the pork for about 12 minutes, until cooked through. The jucies will run clear when the pork is pierced with a skewer.
For the figs and balsamic dressing, heat the sugar and butter in a heavy-bottomed saucepan until they begin to caramelise. Add the balsamic vinegar and stir to form a syrup. Take the pan off the heat and immediately add the figs, pomegranate seeds, orange zest and pistachio nuts, coating them all in the syrup. Set aside.
To serve, slice the pork and serve on watercress with the sauce spooned over with the hot roast potatoes.


mountainAI
an Artificial Intelligence company
mountainAI is an Artificial Intelligence company focused on practical application.
We are developing interfaces and models to apply general and narrow AI in practical B2B and B2C applications.
Comming Soon!!


Gary Danielson Got Blasted On Twitter For Laughing, Mocking Unconscious Photographer During Auburn-Georgia Game (VIDEO + TWEETS)
by Darrelle LincolnGary Danielson is going to need to release a public apology, because this was disgusting.
During the waning seconds of the first half game between the Bulldogs-Tigers — UGA running back Brian Herrien came into contact with a young photographer on the sideline and the collision left her unconscious.
Despite the seriousness of the situation, Danielson took the opportunity to poke fun of the young woman. He seemed to laugh throughout and not really show any concern at all.
Here’s how social media reacted:


var crypto = require('crypto');
/**
* Current version supports only two colours of checkers and two players as
* the author is not yet aware of rules with three or more types of checkers
* and/or players.
* @readonly
* @enum {number}
*/
var PieceType = {
/** White piece */
WHITE : 0,
/** Black piece */
BLACK : 1
};
/**
* Common utilities
* @constructor
*/
function Utils() {
}
/**
* Generate unique ID for an object in model
* @returns {number}
*/
Utils.generateID = function () {
// TODO: Use a better approach - eg. a database ObjectID?
return Math.floor(Math.random() * 99999999);
};
/**
* Sanitize rule's name so that it is safe to use as a filename
* @param {string} name - Rule's name to sanitize (eg. 'RuleBgCasual')
* @returns {string}
*/
Utils.sanitizeName = function (name) {
return name.replace(/[^-_A-Za-z0-9]/gi, "");
};
/**
* Load rule object by path and class name
* @param {string} path - Path where rule files are stored ('../../lib/rules/' in browser sample)
* @param {string} ruleName - Name of rule - equal to rule's class name (eg. 'RuleBgCasual')
* @returns {Rule} - Rule object
*/
Utils.loadRule = function (ruleName) {
var path = './rules/';
var fileName = Utils.sanitizeName(ruleName);
var file = path + fileName + '.js';
console.log('Loading rule in file ' + file);
var rule = require(file);
rule.name = fileName;
console.log(rule);
return rule;
};
/**
* Extract item object from array
* @param {Array} array - Array of elements
* @param {Object} item - Element to remove from array
* @returns {} - The element removed from array or null, if not found
*/
Utils.extractItem = function (array, item) {
for (var i = 0; i < array.length; i++) {
if (array[i] === item) {
array.splice(i, 1);
return;
}
}
};
/**
* Remove item from array
* @param {Array} array - Array of elements
* @param {Object} item - Element to remove from array
*/
Utils.removeItem = function (array, item) {
Utils.extractItem(array, item);
};
/**
* Rotate array elements left.
*
* Example:
* [6, 4, 1] becomes [4, 1, 6]
*
* @param {Array} array - Array of elements
*/
Utils.rotateLeft = function (array) {
array.unshift(array.pop());
};
/**
* Create shallow copy of object.
*
* @param {Object} oldObj - Object to copy
* @returns {Object} - Shallow copy of object
*/
Utils.shallowCopy = function (oldObj) {
var newObj = {};
for(var i in oldObj) {
if(oldObj.hasOwnProperty(i)) {
newObj[i] = oldObj[i];
}
}
return newObj;
};
/**
* Create deep copy of a value object.
* The object should have no functions/methods.
*
* @param {Object} oldObj - Object to copy
* @returns {Object} - Deep copy of object
*/
Utils.deepCopy = function (oldObj) {
return JSON.parse(JSON.stringify(oldObj));
};
/**
* Simulate server load/hosting throttling
*
* @param {Object} oldObj - Object to copy
* @returns {Object} - Deep copy of object
*/
Utils.simulateServerLoad = function () {
for (var i = 0; i < 100000; i++) {
for (var k = 1; k < 1000; k++) {
var q = Math.sqrt(1000000007);
}
}
};
/**
* Get random element from an array
*
* @param {Array} arr - Array to choose element from
* @returns {Object} - Random element in array
*/
Utils.getRandomElement = function (arr) {
var idx = Math.floor(Math.random() * arr.length);
return arr[idx];
};
/**
* Random generator.
* @constructor
*/
function Random() {
}
/**
* Get random number from 1 to 6
* @returns {number} - Random value from 1 to 6
*/
Random.get = function() {
// TODO: replace with quality random generator
// Combine Math random generator with crypto one
var buffer = crypto.randomBytes(1);
var value = buffer.readUInt8(0);
console.log(value);
if (value > 255) {
value = 255;
}
var k = value / 256;
return (Math.floor(k * 6) + 1);
};
/**
* Pieces are round checkers that are being moved around the board.
* @constructor
* @param {PieceType} type - Type of piece
* @param {number} id - ID of piece
*/
function Piece(type, id) {
/**
* Type of piece (white/black)
* @type {PieceType}
*/
this.type = type;
/**
* ID of piece
* @type {number}
*/
this.id = id;
}
/**
* Dice with basic functionality to roll using good random generator.
* @constructor
*/
function Dice() {
/**
* Values of the two dice
* @type {Array}
*/
this.values = [0, 0];
/**
* List of moves the player can make. Usually moves are equal to values,
* but in most rules doubles (eg. 6:6) are played four times, instead of
* two, in which case moves array will contain four values in stead of
* only two (eg. [6, 6, 6, 6]).
* @type {Array}
*/
this.moves = [];
/**
* After dice is rolled, movesLeft contains the same values as moves.
* When the player makes a move, the corresponding value is removed from
* movesLeft array. If the player wants to undo the moves made, movesLeft is
* replaced with moves.
* @type {Array}
*/
this.movesLeft = [];
/**
* After a piece is moved, the value of the die used is added to movesPlayed array.
* @type {Array}
*/
this.movesPlayed = [];
}
/**
* Roll dice and return result as a new Dice object
* @returns {Dice} - New dice with random values
*/
Dice.roll = function() {
var dice = new Dice();
dice.values[0] = Random.get();
dice.values[1] = Random.get();
dice.values.sort(function (a, b) { return b - a; });
return dice;
};
/**
* Roll dice and return result as a new Dice object
* @param {Dice} dice - New dice with random values
* @param {number} move - New dice with random values
*/
Dice.markAsPlayed = function (dice, move) {
for (var i = 0; i < dice.movesLeft.length; i++) {
if (dice.movesLeft[i] === move) {
dice.movesPlayed.push(dice.movesLeft[i]);
dice.movesLeft.splice(i, 1);
return;
}
}
throw new Error("No such move!");
};
/**
* Check if the dice object has double (equal) values.
* @param {Dice} dice - New dice with random values
* @returns {boolean} - True if dice object has dobule values, false otherwise
*/
Dice.isDouble = function (dice) {
return dice.values[0] === dice.values[1];
};
/**
* Get remaining moves from dice object - moves that have not been played.
* @param {Dice} dice - Dice object
* @returns {Array} - Array containing remaining move values
*/
Dice.getRemainingMoves = function (dice) {
var remaining = [];
var played = [];
played = played.concat(dice.movesPlayed);
for (var i = 0; i < dice.moves.length; i++) {
var index = played.indexOf(dice.moves[i]);
if (index >= 0) {
played.splice(index, 1);
}
else {
remaining.push(dice.moves[i]);
}
}
return remaining;
};
/**
* State contains points and pieces and very basic methods to move pieces
* around without enforcing any rules. Those methods are responsible for
* required changes to internal state only, the UI layer should handle
* graphical movement of pieces itself.
* @constructor
*/
function State() {
/**
* All popular variants of the game have a total of 24 positions on the board
* and two positions outside - the place on the bar where pieces go when
* hit and the place next to board where pieces go when beared off.
* Number of positions is not strictly defined here to allow more options
* when creating new rules.
* The points, bar, outside and pieces properties should be initialized by the
* Rule object. Each element in those properties should contain a stack
* (last in, first out).
* @type {Array}
*/
this.points = [];
/**
* Players have separate bar places and so separate list.
* First element of array is for white pieces and second one for black.
* @type {Array[]}
*/
this.bar = [[],[]];
this.whiteBar = this.bar[PieceType.WHITE];
this.blackBar = this.bar[PieceType.BLACK];
/**
* Players have separate outside places and so separate list.
* First element of array is for white pieces and second one for black.
* @type {Array[]}
*/
this.outside = [[],[]];
this.whiteOutside = this.outside[PieceType.WHITE];
this.blackOutside = this.outside[PieceType.BLACK];
/**
* A two dimensional array is also used to store references to all white and
* black pieces independent of their position - just for convenience.
*/
this.pieces = [[],[]];
this.whitePieces = this.pieces[PieceType.WHITE];
this.blackPieces = this.pieces[PieceType.BLACK];
/**
* Counter for generating unique IDs for pieces within this state
* @type {number}
*/
this.nextPieceID = 1;
}
/**
* Clear state
* @param {State} state - Board state
*/
State.clear = function(state) {
state.nextPieceID = 1;
for (var i = 0; i < state.points.length; i++) {
state.points[i].length = 0;
}
state.whiteBar.length = 0;
state.blackBar.length = 0;
state.whiteOutside.length = 0;
state.blackOutside.length = 0;
state.whitePieces.length = 0;
state.blackPieces.length = 0;
};
/**
* Count number of pieces of specified type at selected position
* @param {State} state - Board state
* @param {number} position - Denormalized point position
* @param {PieceType} type - Piece type
* @returns {number} - Number of pieces of specified type
*/
State.countAtPos = function(state, position, type) {
var cnt = 0;
for (var i = 0; i < state.points[position].length; i++) {
if (state.points[position][i].type == type) {
cnt++;
}
}
return cnt;
};
/**
* Count number of all pieces at selected position, regardless of type
* @param {State} state - Board state
* @param {number} position - Denormalized point position
* @returns {number} - Number of pieces of specified type
*/
State.countAllAtPos = function(state, position) {
var cnt = 0;
for (var i = 0; i < state.points[position].length; i++) {
cnt++;
}
return cnt;
};
/**
* Check if there are no pieces at the specified point
* @param {State} state - Board state
* @param {number} position - Denormalized point position
* @returns {boolean} - Returns true if there are no pieces at that point
*/
State.isPosFree = function(state, position) {
return state.points[position].length <= 0;
};
/**
* Get top piece, checking type in the process
* @param {State} state - Board state
* @param {number} position - Denormalized point position
* @param {PieceType} type - Piece type
* @returns {boolean} - Returns true if top piece at position is of the specified type. Returns false if there are no pieces at that point.
*/
State.checkTopPieceType = function(state, position, type) {
if (state.points[position].length > 0) {
var numPieces = state.points[position].length;
var piece = state.points[position][numPieces - 1];
if (piece.type === type) {
return true;
}
}
return false;
};
/**
* Get top piece at specified position
* @param {State} state - Board state
* @param {number} position - Denormalized point position
* @returns {Piece} - Returns type of top piece or null if there are no pieces at that position
*/
State.getTopPiece = function(state, position) {
var point = state.points[position];
//console.log(state, position);
if (point.length === 0) {
return null;
}
return point[point.length - 1];
};
/**
* Get type of top piece at specified position
* @param {State} state - Board state
* @param {number} position - Denormalized point position
* @returns {PieceType} - Returns type of top piece or null if there are no pieces at that position
*/
State.getTopPieceType = function(state, position) {
var point = state.points[position];
//console.log(state, position);
if (point.length === 0) {
return null;
}
return point[point.length - 1].type;
};
/**
* Check if there are any pieces on the bar.
* @param {State} state - State to check
* @param {PieceType} type - Type of piece (white/black)
* @returns {boolean} - True if there are any pieces on the bar
*/
State.havePiecesOnBar = function(state, type) {
return state.bar[type].length > 0;
};
/**
* Check if a specific piece is on the bar.
* @param {State} state - State to check
* @param {Piece} piece - Piece
* @returns {boolean} - True if there are any pieces on the bar
*/
State.isPieceOnBar = function(state, piece) {
var bar = state.bar[piece.type];
for (var i = 0; i < bar.length; i++) {
if (bar[i].id === piece.id) {
return true;
}
}
return false;
};
/**
* Check if the piece is outside.
* @param {State} state - State to check
* @param {Piece} piece - Piece
* @returns {boolean} - True if there are any pieces on the bar
*/
State.isPieceOutside = function(state, piece) {
var outside = state.outside[piece.type];
for (var i = 0; i < outside.length; i++) {
if (outside[i].id === piece.id) {
return true;
}
}
return false;
};
/**
* Get top piece at bar
* @param {State} state - Board state
* @param {PieceType} type - Type of piece (white/black)
* @returns {Piece} - Returns type of top piece or null if there are no pieces at that position
*/
State.getBarTopPiece = function(state, type) {
var point = state.bar[type];
if (point.length === 0) {
return null;
}
return point[point.length - 1];
};
/**
* Get position of piece on board. Return null if the piece is on bar or outside the board.
* @param {State} state - Game
* @param {Piece} piece - Piece
* @returns {number} - Position of piece on board or null if on bar/outside the board
*/
State.getPiecePos = function (state, piece) {
var i, k;
for (i = 0; i < state.points.length; i++) {
for (k = 0; k < state.points[i].length; k++) {
if (state.points[i][k].id === piece.id) {
return i;
}
}
}
return null;
};
/**
* Creates a deep copy of state object
* @param {State} state - Game state
* @returns {State} - New state object
*/
State.clone = function (state) {
var newState = Utils.deepCopy(state);
newState.whiteBar = newState.bar[PieceType.WHITE];
newState.blackBar = newState.bar[PieceType.BLACK];
newState.whiteOutside = newState.outside[PieceType.WHITE];
newState.blackOutside = newState.outside[PieceType.BLACK];
newState.whitePieces = newState.pieces[PieceType.WHITE];
newState.blackPieces = newState.pieces[PieceType.BLACK];
return newState;
};
/**
* Player's statistics
* @constructor
*/
function PlayerStats() {
/**
* Total number of wins
* @type {number}
*/
this.wins = 0;
/**
* Total number of loses
* @type {number}
*/
this.loses = 0;
/**
* Percent of doubles rolled relative to total number of dice rolled
* @type {number}
*/
this.doubles = 0;
}
/**
* Player
* @constructor
*/
function Player() {
/**
* Unique ID
* @type {number}
*/
this.id = 0;
/**
* Username
* @type {string}
*/
this.name = '';
/**
* Reference to current match
* @type {Match}
*/
this.currentMatch = null;
/**
* Reference to current game
* @type {Game}
*/
this.currentGame = null;
/**
* Reference to rule for current game
* @type {Rule}
*/
this.currentRule = null;
/**
* Player's piece type for current game
* @type {PieceType}
*/
this.currentPieceType = null;
/**
* Player's statistics
* @type {PlayerStats}
*/
this.stats = new PlayerStats();
// TODO: Remove socketID from this class
/**
* ID of player's socket
* @type {string}
*/
this.socketID = null;
}
/**
* Create new player object with unique ID.
* Player object is not saved to database.
* @returns {Player} - New player object
*/
Player.createNew = function() {
var player = new Player();
player.id = Utils.generateID();
return player;
};
/**
* Game
* @constructor
*/
function Game() {
/**
* Unique ID of game
* @type {number}
*/
this.id = 0;
/**
* Board state
* @type {State}
*/
this.state = null;
/**
* Flag that shows if game has started
* @type {boolean}
*/
this.hasStarted = false;
/**
* Flag that shows if game is over/has finished
* @type {boolean}
*/
this.isOver = false;
/**
* Number (index) of turn
* @type {number}
*/
this.turnNumber = 0;
/**
* Show which player's turn it is
* @type {Player}
*/
this.turnPlayer = null;
/**
* Dice for current turn. Should be null if dice haven't been rolled yet.
* @type {Dice}
*/
this.turnDice = null;
/**
* Flag that shows if the moves made in current turn have been confirmed by the player.
* @type {boolean}
*/
this.turnConfirmed = false;
/**
* Previous game state, used for undoing moves
*/
this.previousState = null;
/**
* Previous dice state, used for undoing moves
*/
this.previousTurnDice = null;
/**
* Sequence number that is incremented each time a piece is moved during the game
*/
this.moveSequence = 0;
}
/**
* Create new game object with unique ID and initialize it.
* Game object is not saved in database.
* @param {Rule} rule - Rule object to use
* @returns {Game} - A new game object with unique ID
*/
Game.createNew = function(rule) {
var game = new Game();
game.id = Utils.generateID();
Game.init(game, rule);
return game;
};
/**
* Initialize game object
* @param {Game} game - Game to initialize
* @param {Rule} rule - Rule to use
*/
Game.init = function (game, rule) {
game.state = new State();
rule.initialize(game.state);
rule.resetState(game.state);
};
/**
* Check if it is specified player's turn
* @param {Game} game - Game
* @param {Player} player - Specified player
* @returns {boolean} - True if it is specified player's turn
*/
Game.isPlayerTurn = function (game, player) {
return (game.turnPlayer) &&
(player) &&
(game.turnPlayer.id === player.id);
};
/**
* Check if it is specified player's turn, but check by their piece type, and not player object
* @param {Game} game - Game
* @param {PieceType} type - Player's piece type
* @returns {boolean} - True if it is specified player's turn
*/
Game.isTypeTurn = function (game, type) {
return (game.turnPlayer) &&
(game.turnPlayer.currentPieceType === type);
};
/**
* Check if dice has been rolled
* @param {Game} game - Game
* @returns {boolean} - True if dice has been rolled (turnDice is not null)
*/
Game.diceWasRolled = function (game) {
return (game.turnDice != null);
};
/**
* Check if there are more moves to make
* @param {Game} game - Game
* @returns {boolean} - True if there are any moves left to make
*/
Game.hasMoreMoves = function (game) {
return (game.turnDice) &&
(game.turnDice.movesLeft.length > 0);
};
/**
* Check if a specific move value is available in movesLeft
* @param {Game} game - Game
* @param {number} value - Move value to check for
* @returns {boolean} - True if specified move value is available
*/
Game.hasMove = function (game, value) {
return (game.turnDice) &&
(game.turnDice.movesLeft.indexOf(value) > -1);
};
/**
* Store current game state - in case the player wants to undo moves later
* @param {Game} game - Game
*/
Game.snapshotState = function (game) {
game.previousState = State.clone(game.state);
game.previousTurnDice = Utils.deepCopy(game.turnDice);
};
/**
* Restore game state from last snapshot - if player requested to undoing of moves
* @param {Game} game - Game
*/
Game.restoreState = function (game) {
game.state = State.clone(game.previousState);
game.turnDice = Utils.deepCopy(game.previousTurnDice);
};
/**
* Match
* @constructor
*/
function Match() {
/**
* Unique ID of match object
* @type {number}
*/
this.id = 0;
/**
* Player that created the match
* @type {Player}
*/
this.host = null;
/**
* Player that joined the match
* @type {Player}
*/
this.guest = null;
/**
* List of all players participating in the match
* @type {Array}
*/
this.players = [];
/**
* Name of the rule used for current match.
* Equals the class name of the rule (eg. 'RuleBgCasual').
* @type {string}
*/
this.ruleName = '';
/**
* Match length - the score needed to win the match.
* @type {number}
*/
this.length = 5;
/**
* Score of players for current match
* @type {Array}
*/
this.score = [];
/**
* Current game
* @type {Game}
*/
this.currentGame = null;
/**
* Is match over
* @type {boolean}
*/
this.isOver = false;
}
/**
* Create new match object with unique ID and initialize it.
* Match object is not saved in database.
* @param {Rule} rule - Rule object to use
* @returns {Match} - A new match object with unique ID
*/
Match.createNew = function(rule) {
var match = new Match();
match.id = Utils.generateID();
match.ruleName = rule.name;
match.score = [0, 0];
return match;
};
/**
* Create new game for this match. Fill game object with data from match
* Game object is not saved in database.
* @param {Rule} rule - Rule object to use
* @returns {Match} - A new match object with unique ID
*/
Match.createNewGame = function(match, rule) {
var game = Game.createNew(rule);
match.currentGame = game;
return game;
};
/**
* Add host player to match
* @param {Match} match - Match to add player to
* @param {Player} player - Player to add
* @throws Throws error if the match already has a host player
*/
Match.addHostPlayer = function (match, player) {
if (match.host)
{
throw new Error("Match already has a host player!");
}
match.host = player;
match.players.push(player);
};
/**
* Add guest player
* @param {Match} match - Match to add player to
* @param {Player} player - Player to add
* @throws Throws error if the match already has a guest player
*/
Match.addGuestPlayer = function (match, player) {
if (match.guest)
{
throw new Error("Match already has a guest player!");
}
match.guest = player;
match.players.push(player);
};
/**
* Check if specified player is the host of the match
* @param {Match} match - Match
* @param {Player} player - Specified player
* @returns {boolean} - True if there is a host player and their ID matches that of the player parameter
*/
Match.isHost = function (match, player) {
return (match.host) &&
(player) &&
(match.host.id === player.id);
};
/**
* Check if another player has joined the match
* @param {Match} match - Match
* @returns {boolean} - True if a another player has joined the match
*/
Match.hasGuestJoined = function (match) {
return (match.guest != null);
};
/**
* Move action types are determined by rules. This is only a default list
* of actions that are shared by most rules.
* @readonly
* @enum {string}
*/
var MoveActionType = {
/** MOVE: Move piece from one point to another */
MOVE: 'move',
/** RECOVER: Recover piece from bar and place it on board */
RECOVER: 'recover',
/** HIT: Hit opponent's piece and sent it to bar */
HIT: 'hit',
/** BEAR: Bear piece - move it outside the board */
BEAR: 'bear'
};
/**
* Actions that can result from making a piece move.
* Rules can assign additional properties to those, depending on the action
* type
* @constructor
*/
function MoveAction() {
/**
* Action type, depends on rule (eg. move, bear, hit)
* @type {MoveActionType|string}
*/
this.type = '';
}
module.exports = {
'PieceType': PieceType,
'Utils': Utils,
'Random': Random,
'Piece': Piece,
'Dice': Dice,
'State': State,
'PlayerStats': PlayerStats,
'Player': Player,
'Game': Game,
'Match': Match,
'MoveActionType': MoveActionType,
'MoveAction': MoveAction
};