text:
<?php
/**
 *
 * HTML related utilities. HTML markup to RSS markup conversion,
 * simplification of HTML to a short list of legal tags and no
 * dangerous attributes, mailto: obfuscation, word count limit
 * that preserves valid HTML markup, and basic text-to-HTML
 * conversion that preserves line breaks and creates links.
 * doc-to-HTML conversion has been removed as it's out of scope for
 * apostrophePlugin which should contain lightweight stuff only.
 * We should consider putting that out as a separate plugin.
 * @author Tom Boutell <tom@punkave.com>
 * @package    apostrophePlugin
 * @subpackage    toolkit
 */
class aHtmlNotHtmlException extends Exception
{

}/**
 * @package    apostrophePlugin
 * @subpackage    toolkit
 * @author     P'unk Avenue <apostrophe@punkave.com>
 */
class aHtml
{
  static private $badPunctuation = array('"', '"', '®', ''', ''');
  static private $badPunctuationReplacements = array('&lquot;', '&rquot;', '®', '‘', '’');

  static private $rssEntityMap =
    array('&lquot;' => '\"',
      '&rquot;' => '\"',
      '®' => '(Reg TM)',
      '‘' => '\'',
      '’' => '\'',
      '&bull' => '*',
      '&' => '&',
      '<' => '<',
      '>' => '>'
    );

  /**
   * Right now this just converts obscure HTML entities to
   * simpler stuff that all feed readers will digest.
   * @param mixed $doc
   * @return mixed
   */
  public static function htmlToRss($doc)
  {
    // Eval stuff like this is not the quickest. There
    // must be a better way. We should be saving a
    // pre-RSSified version of posts, for one thing.
    return preg_replace(
      '/(&\w+;)/e',
      "aHtml::entityToRss('$1')",
      $doc);
  }

  /**
   * DOCUMENT ME
   * @param mixed $entity
   * @return mixed
   */
  public static function entityToRss($entity)
  {
    if (isset(self::$rssEntityMap[$entity]))
    {
      return self::$rssEntityMap[$entity];
    }
    else
    {
      return '';
    }
  }

  // The default list of allowed tags for aHtml::simplify().
  // These work well for user-generated content made with FCK.
  // You can now alter this list by passing a similar list as the second
  // argument to aHtml::simplify(). An array of tag names without braces is also allowed.

  // Reserving h1 and h2 for the site layout's use is generally a good idea

  static private $defaultAllowedTags =
    '

<nl>

';

  // The default list of allowed attributes for aHtml::simplify().
  // You can now alter this list by passing a similar array as the fourth
  // argument to aHtml::simplify().

  static private $defaultAllowedAttributes = array(
    "a" => array("href", "name", "target"),
    "img" => array("src")
  );

  // Subtle control of the style attribute is possible, but we don't allow
  // any styles by default. See the allowedStyles argument to simplify()

  static private $defaultAllowedStyles = array();

  // allowedTags can be an array of tag names, without < and > delimiters,
  // or a continuous string of tag names bracketed by < and > (as strip_tags
  // expects).

  // By default, if the 'a' tag is in allowedTags, then we allow the href attribute on
  // that (but not JavaScript links). If the 'img' tag is in allowedTags,
  // then we allow the src attribute on that (but no JavaScript there either).
  // You can alter this by passing a different array of allowed attributes.

  // If $complete is true, the returned string will be a complete
  // HTML 4.x document with a doctype and html and body elements.
  // otherwise, it will be a fragment without those things
  // (which is what you almost certainly want).

  // If $allowedAttributes is not false, it should contain an array in which the
  // keys are tag names and the values are arrays of attribute names to be permitted.
  // Note that javascript: is forbidden at the start of any attribute, so attributes
  // that act as URLs should be safe to permit (we now check for leading space and
  // mixed case variations of javascript: as well).

  // If $allowedStyles is not false, it should contain an array in which the keys
  // are tag names and the values are arrays of CSS style property names to be permitted.
  // This is a much better idea than just allowing the style attribute, which is one
  // of the best ways to kill the layout of an entire page.
  //
  // An example:
  //
  // array("table" => array("width", "height"),
  //   "td" => array("width", "height"),
  //   "th" => array("width", "height"))
  //
  // Note that rich text editors vary in how they handle table width and height;
  // Safari sets the width and height attributes of the tags rather than going
  // the CSS route. The simplest workaround is to allow that too.

  // loadHtml, in its infinite wisdom, insists on giving us br tags
  // without a proper /> at the end. Force a fix by default (thanks to
  // Geoff Hammond). This is done in a simple way that would have problems
  // if you were allowing script elements, but why would you do such a foolish thing?
  static private $defaultHtmlStrictBr = true;

  /**
   * DOCUMENT ME
   * @param mixed $value
   * @param mixed $allowedTags
   * @param mixed $complete
   * @param mixed $allowedAttributes
   * @param mixed $allowedStyles
   * @param mixed $htmlStrictBr
   * @return mixed
   */
  static public function simplify($value, $allowedTags = false, $complete = false, $allowedAttributes = false, $allowedStyles = false, $htmlStrictBr = false)
  {
    if ($allowedTags === false)
    {
      // Not using Symfony? Replace the entire sfConfig::get call with self::$defaultAllowedTags
      $allowedTags = sfConfig::get('app_aToolkit_allowed_tags', self::$defaultAllowedTags);
    }
    if ($allowedAttributes === false)
    {
      // See above
      $allowedAttributes = sfConfig::get('app_aToolkit_allowed_attributes', self::$defaultAllowedAttributes);
    }
    if ($allowedStyles === false)
    {
      // See above
      $allowedStyles = sfConfig::get('app_aToolkit_allowed_styles', self::$defaultAllowedStyles);
    }
    if ($htmlStrictBr === false)
    {
      // See above
      $htmlStrictBr = sfConfig::get('app_aToolkit_html_strict_br', self::$defaultHtmlStrictBr);
    }
    $value = trim($value);
    if (!strlen($value))
    {
      // An empty string is NOT something to panic
      // and generate warnings about
      return '';
    }
    if (is_array($allowedTags))
    {
      $tags = "";
      foreach ($allowedTags as $tag)
      {
        $tags .= "<$tag>";
      }
      $allowedTags = $tags;
    }
    $value = strip_tags($value, $allowedTags);

    // Now we use DOMDocument to strip attributes. In principle of course
    // we could do the whole job with DOMDocument. But in practice it is quite
    // awkward to hoist subtags correctly when a parent tag is not on the
    // allowed list with DOMDocument, and strip_tags takes care of that
    // task just fine.

    // At first I used matt@lvi.org's function from the strip_tags
    // documentation wiki. Unfortunately preg_replace tends to return null
    // on some of his regexps for nontrivial documents which is pretty
    // disastrous. He seems to have some greedy regexps where he should
    // have ungreedy regexps. Let's do it right rather than trying to
    // make regular expressions do what they shouldn't.

    // We also get rid of javascript: links here, a good idea from
    // Matt's script.

    $oldHandler = set_error_handler("aHtml::warningsHandler", E_WARNING);

    // If we do not have a properly formed  document then
    // UTF-8 encoded content will be trashed. This is important because we support fragments
    // of HTML containing UTF-8 as part of a
    if (!preg_match("//i", $value))
    {
      $value = '

      <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

      ' . $value . '

      ';
    }
    try
    {
      // Specify UTF-8 or UTF-8 encoded stuff passed in will turn into sushi.
      $doc = new DOMDocument('1.0', 'UTF-8');
      $doc->strictErrorChecking = true;
      $doc->loadHTML($value);
      self::stripAttributesNode($doc, $allowedAttributes, $allowedStyles);
      // Per user contributed notes at
      // http://us2.php.net/manual/en/domdocument.savehtml.php
      // saveHTML forces a doctype and container tags on us; get
      // rid of those as we only want a fragment here
      $result = $doc->saveHTML();
    } catch (aHtmlNotHtmlException $e)
    {
      // The user thought they were entering text and used & accordingly (as they so often do)
      $result = htmlspecialchars($value);
    }

    if ($complete)
    {
      // Don't allow whitespace to balloon
      $result = trim($result);
    }
    else
    {
      $result = self::documentToFragment($result);
    }

    // Browser RTEs insert

 at the beginning and
    //

 at the end to work around bugs in the actual rich text
    // editing component in the browser. Pull this brain damage back out

    $result = preg_replace(array('|^\s*
\s* \s*
|s', '|
\s* \s*
\s*$|s'), array('', ''), $result);

    // Browser RTEs love to insert

 where
 is all they really need.
    // There are more elaborate cases we don't mess with because
    // introducing a
 as a replacement for

 would not
    // have the same impact (an h4-sized gap between two h4s). Tested across
    // browsers. Fixes #500
    $result = preg_replace('|
\s* \s*
|s', '
', $result);

    if($htmlStrictBr)
    {
      $result = str_replace('
', '
', $result);
    }

    if ($oldHandler)
    {
      set_error_handler($oldHandler);
    }
    return $result;
  }

  /**
   * DOCUMENT ME
   * @param mixed $s
   * @return mixed
   */
  static public function documentToFragment($s)
  {
    // Added trim call because otherwise size begins to balloon indefinitely
    return trim(preg_replace(array('/^<!DOCTYPE.+?>/', '/.*?<\/head>/i'), '',
      str_replace( array('', '', '', ''), array('', '', '', ''), $s)));
  }

  /**
   * DOCUMENT ME
   * @param mixed $errno
   * @param mixed $errstr
   * @param mixed $errfile
   * @param mixed $errline
   * @return mixed
   */
  static public function warningsHandler($errno, $errstr, $errfile, $errline)
  {
    // Most warnings should be ignored as DOMDocument cleans up the HTML in exactly
    // the way we want. However "no name in entity" usually means the user thought they
    // were entering plaintext, so we should throw an exception signaling that

    if (strstr("no name in Entity", $errstr))
    {
      throw new aHtmlNotHtmlException();
    }
    return;
  }

  /**
   * DOCUMENT ME
   * @param mixed $node
   * @param mixed $allowedAttributes
   * @param mixed $allowedStyles
   */
  static private function stripAttributesNode($node, $allowedAttributes, $allowedStyles)
  {
    if ($node->hasChildNodes())
    {
      foreach ($node->childNodes as $child)
      {
        self::stripAttributesNode($child, $allowedAttributes, $allowedStyles);
      }
    }
    if ($node->hasAttributes())
    {
      $removeList = array();
      foreach ($node->attributes as $index => $attr)
      {
        $good = false;
        if ($attr->name === 'style')
        {
          if (isset($allowedStyles[$node->nodeName]))
          {
            // There is no handy function in core PHP to parse CSS rules, so we'll do it ourselves

            // First chop it into raw tokens as follows: /* ... */, \', \", ;, :, ', " and anything else
            $styles = array();
            $rawTokens = preg_split('/(\/\*.*?\*\/|\\\'|\\\"|;|:|\'|")/', $attr->value, null, PREG_SPLIT_DELIM_CAPTURE);
            // Now assemble quoted strings into single tokens, inclusive of escaped quotes, ;, :, etc. so that
            // we don't get tripped up by them later
            $realTokens = array();
            $single = false;
            $double = false;
            $s = '';
            foreach ($rawTokens as $rawToken)
            {
              if ($rawToken === "'")
              {
                if ($single)
                {
                  $single = false;
                  $realTokens[] = "'" . $s . "'";
                }
                else
                {
                  $single = true;
                  $s = '';
                }
              }
              elseif ($rawToken === '"')
              {
                if ($double)
                {
                  $double = false;
                  $realTokens[] = '"' . $s . '"';
                }
                else
                {
                  $double = true;
                  $s = '';
                }
              }
              else
              {
                if ($single || $double)
                {
                  $s .= $rawToken;
                }
                else
                {
                  $realTokens[] = $rawToken;
                }
              }
            }
            // Now we can just scan for semicolons and colons and make pretty rules
            $styles = array();
            $state = 'property';
            $p = '';
            $v = '';
            if (end($realTokens) !== ';')
            {
              $realTokens[] = ';';
            }
            foreach ($realTokens as $token)
            {
              if ($state === 'property')
              {
                if ($token === ':')
                {
                  $state = 'value';
                }
                else
                {
                  // We dump comments. Seems like a good idea in a tool used to clean up
                  // rich text editor output. If we didn't do this, we'd need a way to
                  // preserve them while still comparing names correctly
                  if (substr($token, 0, 2) !== '/*')
                  {
                    $p .= $token;
                  }
                }
              }
              elseif ($state === 'value')
              {
                if ($token === ';')
                {
                  // TODO: unescape quotes and unicode escapes in property names so
                  // we can compare them to the allowed properties, then reescape them
                  // when assembling the final rules.
                  //
                  // Not that hard given the tokenizing we've already done,
                  // but rich text editors don't generally introduce that nonsense
                  // into style attributes
                  $p = trim($p);
                  $styles[$p] = $v;
                  $p = '';
                  $v = '';
                  $state = 'property';
                }
                else
                {
                  // We dump comments. Seems like a good idea in a tool used to clean up
                  // rich text editor output
                  if (substr($token, 0, 2) !== '/*')
                  {
                    $v .= $token;
                  }
                }
              }
              else
              {
                throw new sfException('Unknown state in CSS parser in stripAttributesNode: ' . $state);
              }
            }
            $allowed = array_flip($allowedStyles[$node->nodeName]);
            $newStyles = array();
            foreach ($styles as $p => $v)
            {
              if (isset($allowed[$p]))
              {
                $newStyles[$p] = $v;
              }
            }
            $good = true;
            $rules = array();
            foreach ($newStyles as $p => $v)
            {
              $rules[] = "$p: $v;";
            }
            $attr->value = implode(' ', $rules);
          }
        }
        if (!$good)
        {
          if (isset($allowedAttributes[$node->nodeName]))
          {
            foreach ($allowedAttributes[$node->nodeName] as $attrName)
            {
              // Be more careful about this: leading space is tolerated by the browser,
              // so is mixed case in the protocol name (at least in Firefox and Safari,
              // which is plenty bad enough)
              if (($attr->name === $attrName) && (!preg_match('/^\s*javascript:/i', $attr->value)))
              {
                // We keep this one
                $good = true;
              }
            }
          }
        }
        if (!$good)
        {
          // Off with its head
          $removeList[] = $attr->name;
        }
      }
      foreach ($removeList as $name)
      {
        $node->removeAttribute($name);
      }
    }
  }

  // TODO: limitWords currently might not do a great job on typical
  // "gross" HTML without closing
 tags and the like.

  static private $nonContainerTags = array(
    "br" => true,
    "img" => true,
    "input" => true
  );

  /**
   * DOCUMENT ME
   * @param mixed $string
   * @param mixed $word_limit
   * @param mixed $options
   * @return mixed
   */
  public static function limitWords($string, $word_limit, $options = array())
  {
    # TBB: tag-aware, doesn't split in the middle of tags
    # (we will probably use fancier tags with attributes later,
    # so this is important). Tags must be valid XHTML unless
    # all allowed tags
    $words = preg_split("/(\<.*?\>|\s+)/", $string, -1,
      PREG_SPLIT_DELIM_CAPTURE);
    $wordCount = 0;
    # Balance tags that need balancing. We don't have strict XHTML
    # coming from OpenOffice (oh, if only) so we'll have to keep a
    # list of the tags that are containers.
    $open = array();
    $result = "";
    $count = 0;
    $num_words = count($words);

    $shortEnough = true;

    foreach ($words as $word) {
      if ($count > $word_limit) {
        $shortEnough = false;
        break;
      } elseif (preg_match("/\<.*?\/\>/", $word)) {
        # XHTML non-container tag, we don't have to guess
        $result .= $word;
        continue;
      } elseif (preg_match("/\<(\w+)/s", $word, $matches)) {
        $tag = $matches[1];
        $result .= $word;
        if (isset(aHtml::$nonContainerTags[$tag])) {
          continue;
        }
        $open[] = $tag;
      } elseif (preg_match("/\<\/(\w+)/s", $word, $matches)) {
        $tag = $matches[1];
        if (!count($open)) {
          # Groan, extra close tag, ignore
          continue;
        }
        $last = array_pop($open);
        if ($last !== $tag) {
          # They closed the wrong tag. Again, ignore for now, but
          # we might want to work on a better solution
          continue;
        }
        $result .= $word;
      } elseif (preg_match("/^\s+$/s", $word)) {
        $result .= $word;
      } else {
        if (strlen($word)) {
          $count++;
          $result .= $word;
        }
      }
    }

    if ($shortEnough)
    {
      // Leave it totally untouched if it is short enough.
      // Now you can use !== to see if it changed anything.
      return $string;
    }

    $append_ellipsis = false;
    if (isset($options['append_ellipsis']))
    {
      $append_ellipsis = $options['append_ellipsis'];
    }
    if ($append_ellipsis == true && $num_words > $word_limit)
    {
      $result .= '…';
    }

    for ($i = count($open) - 1; ($i >= 0); $i--) {
      $result .= "</" . $open[$i] . ">";
    }
    return $result;
  }

  /**
   * This is a quick and dirty implementation based on calling limitWords
   * with an optimistic guess and then backing off a few times if necessary
   * until we get under the byte limit. Note that limitBytes is designed
   * to fit things in buffers, not save screen space, so it does have to
   * make sure the result is not too big
   * @param mixed $string
   * @param mixed $byte_limit
   * @param mixed $options
   * @return mixed
   */
  public static function limitBytes($string, $byte_limit, $options = array())
  {
    $word_limit = (int) ($byte_limit / 8);
    while (true)
    {
      $s = aHtml::limitWords($string, $word_limit, $options);
      if (strlen($s) <= $byte_limit)
      {
        break;
      }
      $word_limit = (int) ($word_limit * 0.75);
    }
    return $s;
  }

  /**
   * DOCUMENT ME
   * @param mixed $html
   * @return mixed
   */
  public static function toText($html)
  {
    # Nothing fancy, we use the text for indexing only anyway.
    # It would be nice to do a prettier job here for future applications
    # that need pretty plaintext representations. That would be useful
    # as an alt-body in emails. This does not entity-decode. See
    // toPlaintext for that
    $txt = strip_tags($html);
    return $txt;
  }

  /**
   * DOCUMENT ME
   * @param mixed $html
   * @return mixed
   */
  public static function obfuscateMailto($html)
  {
    # Obfuscates any mailto: links found in $html. Good if you already
    # have nice HTML from FCK or what have you.

    # Note that this updated version is AJAX-friendly
    # (it does not use document.write). Also, it preserves
    # the innerHTML of the original link rather than forcing it
    # to be the address found in the href.

    # ACHTUNG: mailto links will become simply
    # whatever-was-inside (in the final
    # presentation to the user, after obfuscation via javascript).
    # If there are other attributes on the  tag they will get tossed out.
    # This is usually not a problem for code that
    # comes from FCK etc. If it is a problem for you, make
    # this method smarter. Also consider just wrapping the link in
    # a span or div, which will not lose its class, id, etc. TBB

    return preg_replace_callback("/\]*?href=\"mailto\:(.*?)\@(.*?)\".*?\>(.*?)\<\/a\>/is",
      array('aHtml', 'obfuscateMailtoInstance'),
      $html);
  }

  /**
   * DOCUMENT ME
   * @param mixed $args
   * @return mixed
   */
  public static function obfuscateMailtoInstance($args)
  {
    list($user, $domain, $label) = array_slice($args, 1);
    // We get some weird escaping problems without the trims
    $user = trim($user);
    $domain = trim($domain);
    // Cripes... crc has to include user, domain *and* label to make it unique.
    // This is worth it to produce cacheable content though
    $class = 'a-email-' . sprintf("%u", crc32($user . '@' . $domain . ':' . $label));
    $href = "mailto:$user@$domain";
    if (sfConfig::get('app_a_inline_obfuscate_mailto'))
    {
      $result = '';
    }
    else
    {
      // This is an acceptable way to stub in a js call for now, since it's the
      // way the helper has to do it too
      $result = "";
      $label = rawurlencode(trim($label));
      $href = rawurlencode($href);
      aTools::$jsCalls[] = array('callable' => 'apostrophe.unobfuscateEmail(?, ?, ?)', 'args' => array($class, $href, $label));
    }
    return $result;
  }

  /**
   * This is intentionally obscure for use in mailto: obfuscators.
   * For an efficient way to pass data to javascript, use json_encode
   * @param mixed $str
   * @return mixed
   */
  static public function jsEscape($str)
  {

    $new_str = '';

    for($i = 0; ($i < strlen($str)); $i++) {
      $new_str .= '\\x' . dechex(ord(substr($str, $i, 1)));
    }

    return $new_str;
  }

  /**
   *
   * This method assumes your text is NOT entity escaped yet. See htmlTextToHtml if your text is
   * already entity escaped.
   *
   * Just the basics: escape entities, turn URLs into links, and turn newlines into line breaks.
   * Also turn email addresses into links (we don't obfuscate them here as that makes them
   * harder to manipulate some more, but check out aHtml::obfuscateMailto).
   *
   * This function is now a wrapper around TextHelper, except for the entity escape which is
   * not included in simple_format_text, probably because of automatic entity escaping in Symfony
   *
   * @param string $text The text you want converted to basic HTML.
   * @param bool $newlines If true, convert newlines to line breaks (call simple_format_text).
   * @return string Text with br tags and anchor tags.
   */
  static public function textToHtml($text, $newlines = true)
  {
    $text = aHtml::entities($text);
    return aHtml::htmlTextToHtml($text, $newlines);
  }

  /**
   *
   * Unlike textToHtml, this method assumes its input is ALREADY entity escaped, and that
   * you just want newlines and links added to that. This is not an uncommon scenario.
   *
   * Just the basics: turn URLs into links, and turn newlines into line breaks.
   * Also turn email addresses into links (we don't obfuscate them here as that makes them
   * harder to manipulate some more, but check out aHtml::obfuscateMailto).
   *
   * This function is now a wrapper around TextHelper
   *
   * @param string $text The text you want converted to basic HTML.
   * @param bool $newlines If true, convert newlines to line breaks (call simple_format_text).
   * @return string Text with br tags and anchor tags.
   */
  static public function htmlTextToHtml($text, $newlines = true)
  {
    sfContext::getInstance()->getConfiguration()->loadHelpers(array('Tag', 'Text'));
    if ($newlines)
    {
      $text = simple_format_text($text);
    }
    return auto_link_text($text);
  }

  /**
   * Convert anything that looks like a hostname into a proper URL so that
   * textToHtml will pick up on it and turn it into a link if called next.
   * Tom chipped this in from his wejoinem project 10/21/11
   * @param string $text
   * @return string
   */
  static public function lazyUrls($text)
  {
    $text = preg_replace_callback('/([a-z]+:\/\/)?[A-Za-z0-9\-]+\.[A-Za-z0-9\-\.]+(\/\S*)?/', array('aHtml', '_cleanupUrl'), $text);
    return $text;
  }

  /**
   * Callback for lazyUrls, not really public. Handles one match, converting a hostname
   * to a URL if it isn't already. Tom chipped this in from his wejoinem project 10/21/11
   */
  static public function _cleanupUrl($matches)
  {
    $url = $matches[0];
    if (!preg_match('/[a-z]+\:/', $url))
    {
      $url = 'http://' . $url;
    }
    return $url;
  }

  /**
   * UTF-8 entity escapes the provided text, and nothing else
   */
  static public function entities($text)
  {
    return htmlentities($text, ENT_COMPAT, 'UTF-8');
  }

  /**
   * For any given HTML, returns only the img tags. If
   * format is set to array, the result is returned as an array
   * in which each element is an associative array with, at a
   * minimum, a src attribute and also width, height, alt and title
   * attributes if they were present in the tag. If format
   * is set to html, an array of the original  tags
   * is returned without further processing.
   * @param mixed $html
   * @param mixed $format
   * @return mixed
   */
  static public function getImages($html, $format = 'array')
  {
    $allowed = array_flip(array("src", "width", "height", "title", "alt"));
    if (!preg_match_all("/\/i", $html, $matches, PREG_PATTERN_ORDER))
    {
      return array();
    }
    $images = $matches[0];
    if (empty($images))
    {
      return array();
    }

    if ($format == 'array')
    {
      $images_info = array();
      foreach ($images as $image)
      {
        // Use a backreference to make sure we match the same
        // type of quote beginning and ending
        preg_match_all('/(\w+)\s*=\s*(["\'])(.*?)\2/',
          $image,
          $matches,
          PREG_SET_ORDER);
        $attributes = array();
        foreach ($matches as $attributeRaw)
        {
          $name = strtolower($attributeRaw[1]);
          $value = $attributeRaw[3];
          if (!isset($allowed[$name]))
          {
            continue;
          }
          $attributes[$name] = $value;
        }
        if (!isset($attributes['src']))
        {
          continue;
        }
        $images_info[] = $attributes;
      }

      return $images_info;
    }

    return $images;
  }

  /**
   * Converts input string to true plaintext (BE CAREFUL: use aHtml::entities() if you display
   * it later). Nonbreaking spaces become vanilla spaces, tags re removed and entities are
   * decoded according to UTF-8
   * @param string $html
   * @return string
   */
  static public function toPlaintext($html)
  {
    // Nonbreaking spaces don't work properly
    // in a lot of contexts where plaintext is
    // needed
    return html_entity_decode(str_replace(' ', ' ', strip_tags($html)), ENT_COMPAT, 'UTF-8');
  }

  /**
   * Accepts an embed code from a service like Wufoo or Etsy and attempts to fix it to
   * be loaded safely via AJAX. document.write() is temporarily overridden to append
   * content to the specified selector rather than blanking the entire page, and any
   * 'script src' tags are converted to jQuery.getScript() calls. This doesn't work
   * for every possible edge case but it is often effective.
   *
   * If the embed code makes document.write() calls to dynamically insert more
   *  tags, capture their src URL, and
    // remove them from the markup. These don't work as-is in AJAX responses

    $count = preg_match_all('||', $code, $matches);
    if ($count)
    {
      $srcs = $matches[1];
      $code = preg_replace('||', '', $code);
    }
    else
    {
      $srcs = array();
    }

    // Build up the response by successively decorating it from the inside out. First the
    // simple append call to add the markup to the selector, then the jQuery.getScript calls
    // to load the required javascripts, and then the logic to override document.write() to
    // also append to the selector

    $escapedSelector = json_encode($appendToSelector);
    $escapedCode = json_encode($code);

    $result = <<<EOM
$($escapedSelector).append($escapedCode);
$($escapedSelector).append(apostropheDocumentWriteBuffer);
document.write = apostropheSaveDocumentWrite;
EOM
;
    // Reverse the order so that the file that should be loaded first is the outermost
    // getScript() call
    $srcs = array_reverse($srcs);

    foreach ($srcs as $src)
    {
      $escapedSrc = json_encode($src);
      $result = <<<EOM
jQuery.getScript($escapedSrc, function() {
  $result
});
EOM
;
    }

    // If they make dynamic document.write calls to generate script src tags,
    // flag that to be special-cased at a higher level. I have some bad news:
    // there is no reliable way to synchronously load js files from another domain
    // (read that whole sentence carefully please) and jQuery doesn't try, even if
    // the async flag is false. So we really can't fix this automagically.

    if ((!isset($options['ignoreDynamicScriptSrc'])) || (!$options['ignoreDynamicScriptSrc']))
    {
      $catchDynamicScriptSrc = <<<EOM
      var scriptSrcRegex = /


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN""http://www.w3.org/TR/REC-html40/frameset.dtd">

<TITLE>
ELENA Standard Library 5.8: Module system'routines
</TITLE>
<meta name="collection" content="api">
<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">

Overview

Module

ELENA Standard Library
5.8

Module system'routines

Class Summary

Class name
Description

Accumulating

Class Accumulating

ArraySortingAgent

sealed Class ArraySortingAgent

BasePattern

Interface BasePattern

Filter

Class Filter

GroupingEnumerator

Class GroupingEnumerator

IndexerSortingAgent

sealed Class IndexerSortingAgent

IntervalEnumerator

Class IntervalEnumerator

JoinEnumerator

Class JoinEnumerator

OrderingEnumerator

Class OrderingEnumerator

PatternFilter2

Class PatternFilter2

PatternFilter3

Class PatternFilter3

PatternFilter4

Class PatternFilter4

PatternFilter5

Class PatternFilter5

PatternFilter6

Class PatternFilter6

QuickSorting

sealed Singleton QuickSorting

RangeEnumerator

Class RangeEnumerator

Repeater

Class Repeater

Selector

Class Selector

SkipFilter

Class SkipFilter

SortingAgent

Interface SortingAgent

Summing

Class Summing

TopFilter

Class TopFilter

ZipEnumerator

Class ZipEnumerator

ifDecrescent

sealed Class ifDecrescent

ifOrdered

sealed Class ifOrdered

Symbol Summary

Symbol name
Description

#ext_initializer

#ext_initializer

Extended Class Summary

Extended class name
Description

Object

Object

Enumerator

Enumerator

String

String

WideString

WideString

Overview

Module

ELENA Standard Library
5.8

redpajama_set_name: RedPajamaGithub


text:
namespace CC
{
namespace Base
{

class Noncopyable
{
public:
    Noncopyable(const Noncopyable&) = delete;
    void operator=(const Noncopyable&) = delete;
};

class Copyable
{
};

}//namespace Base
}//namespace CC

#define CC_NONCOPYABLE_H_
#endif//CC_NONCOPYABLE_H_


text:
package org.apache.rocketmq.client;

import java.util.Set;
import java.util.TreeSet;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.log.ClientLogger;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import org.slf4j.Logger;

public class MQHelper {
    public static void resetOffsetByTimestamp(
        final MessageModel messageModel,
        final String consumerGroup,
        final String topic,
        final long timestamp) throws Exception {
        resetOffsetByTimestamp(messageModel, "DEFAULT", consumerGroup, topic, timestamp);
    }

    /**
     * Reset consumer topic offset according to time
     *
     * @param messageModel which model
     * @param instanceName which instance
     * @param consumerGroup consumer group
     * @param topic topic
     * @param timestamp time
     * @throws Exception
     */
    public static void resetOffsetByTimestamp(
        final MessageModel messageModel,
        final String instanceName,
        final String consumerGroup,
        final String topic,
        final long timestamp) throws Exception {
        final Logger log = ClientLogger.getLog();

        DefaultMQPullConsumer consumer = new DefaultMQPullConsumer(consumerGroup);
        consumer.setInstanceName(instanceName);
        consumer.setMessageModel(messageModel);
        consumer.start();

        Set<MessageQueue> mqs = null;
        try {
            mqs = consumer.fetchSubscribeMessageQueues(topic);
            if (mqs != null && !mqs.isEmpty()) {
                TreeSet<MessageQueue> mqsNew = new TreeSet<MessageQueue>(mqs);
                for (MessageQueue mq : mqsNew) {
                    long offset = consumer.searchOffset(mq, timestamp);
                    if (offset >= 0) {
                        consumer.updateConsumeOffset(mq, offset);
                        log.info("resetOffsetByTimestamp updateConsumeOffset success, {} {} {}",
                            consumerGroup, offset, mq);
                    }
                }
            }
        } catch (Exception e) {
            log.warn("resetOffsetByTimestamp Exception", e);
            throw e;
        } finally {
            if (mqs != null) {
                consumer.getDefaultMQPullConsumerImpl().getOffsetStore().persistAll(mqs);
            }
            consumer.shutdown();
        }
    }
}


text:
<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $model backend\models\Events */
/* @var $form yii\widgets\ActiveForm */
?>

    <?php $form = ActiveForm::begin(); ?>

    <?= $form->field($model, 'title')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'text')->textarea(['rows' => 6]) ?>

    <?= $form->field($model, 'created_date')->textInput() ?>

        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>

    <?php ActiveForm::end(); ?>


text:
from collections import OrderedDict

#------------------------
# variables:
#------------------------

words = OrderedDict()
words['Eng'] = ''
words['Chi'] = ''
words['Spa'] = ''
words['Hin'] = ''
words['Ara'] = ''
words['Rus'] = ''

originalWords = words

wordsMinusNoninitialVowels = words

shortList = []

newWord = ''

filename = 'data.txt'

allophones = {
    'aeiou' : 'a',
    'bp' : 'b',
    'cjsz' : 'z',
    'dt' : 'd',
    'fv' : 'v',
    'gkq' : 'g',
    'hx' : 'h',
    'lr' : 'l',
    'mn' : 'm',
    'w' : 'w',
    'y' : 'y'
    }

#------------------------
# methods:
#------------------------

def respellWithInitialVowelAndConsonants(word):
    for char in word[1:]:
        if char in 'aeiou':
            word = word[0] + word[1:].replace(char,'')
    return word

def respellWithAllophones(word):
    for char in word:
        for allo in allophones:
            if char in allo:
                word = word.replace(char,allophones[allo])
    return word

def combineOverlappingWords(shortList):
    for language in shortList:
        for otherlanguage in shortList:
            if language != otherlanguage and language != 'Eng' and otherlanguage != 'Eng':
                a = shortList[language]
                b = shortList[otherlanguage]
                for i in range(1, len(b)):
                    if a.endswith(b[:i]):
                        shortList[otherlanguage] = ''
                        shortList[language] = a+b[i:]
    return shortList

#------------------------
# main part of the program:
#------------------------

# get lines of file into a list:
with open(filename,'r') as fh:
    data = fh.readlines()

# fill arrays:
for line in data:
    words['Eng'] = line.split(',')[1]
    words['Chi'] = line.split(',')[2]
    words['Spa'] = line.split(',')[3]
    words['Hin'] = line.split(',')[4]
    words['Ara'] = line.split(',')[5]
    words['Rus'] = line.split(',')[6]
    if words['Eng'] == 'be':
        break # get rid of this break condition in later versions of code

originalWords = words.copy() # must explicitly make copy of dictionary in Python (instead of a reference)

# show the words:
print '\nshow the words:'

for language in words:
    if language != 'Eng':
        print language + '\t' + words[language]

# show the words spelt with just the initial vowel and consonants:
print '\nshow the words spelt with just the initial vowel and consonants:'

for language in words:
    if language != 'Eng':
        words[language] = respellWithInitialVowelAndConsonants(words[language])
        print language + '\t' + words[language]

wordsMinusNoninitialVowels = words.copy() # must explicitly make copy of dictionary in Python (instead of a reference)

# show the words with allophonic spelling:
print '\nshow the words with allophonic spelling:'

for language in words:
    if language != 'Eng':
        words[language] = respellWithAllophones(words[language])
        print language + '\t' + words[language]

# ignore repeats:
print '\nignore repeats:'

shortList = words

for language in shortList:
    for otherlanguage in shortList:
        if language != otherlanguage and language != 'Eng' and otherlanguage != 'Eng':
            if shortList[language] == shortList[otherlanguage]:
                shortList[otherlanguage] = ''

for language in shortList:
    if language != 'Eng':
        print language + '\t' + shortList[language] # print the unique words

# ignore words embedded in other words:
print '\nignore words embedded in other words:'

for language in shortList:
    for otherlanguage in shortList:
        if language != otherlanguage and language != 'Eng' and otherlanguage != 'Eng':
            if shortList[language] in shortList[otherlanguage]:
                shortList[language] = ''

for language in shortList:
    if language != 'Eng':
        print language + '\t' + shortList[language]

# find overlaps in words:

for tries in range(5):
    print '\nfind overlaps in words:  try #' + str(tries+1)

    shortList = combineOverlappingWords(shortList)

    for language in shortList:
        if language != 'Eng':
            print language + '\t' + shortList[language]

# append remaining words:
print '\nappend remaining words:'

for language in shortList:
    if language != 'Eng':
        newWord += shortList[language]

print newWord

# put original consonants back in, using 1st letters of higher-priority words:
print '\nput original consonants back in, using 1st letters of higher-priority words:'
#print
#print 'originalWords = \n', originalWords, '\n'
#print 'wordsMinusNoninitialVowels = \n', wordsMinusNoninitialVowels, '\n'
#print 'words = \n', words, '\n'
print words
for language in reversed(words.keys()):
    if language != 'Eng':
        print wordsMinusNoninitialVowels[language]
        patternCompressedAllo = respellWithAllophones(wordsMinusNoninitialVowels[language])
        if wordsMinusNoninitialVowels[language] not in newWord:
            if patternCompressedAllo in respellWithAllophones(newWord): # replace with compressed word in allophone form
                index = respellWithAllophones(newWord).find(patternCompressedAllo)
                newWord = newWord[:index] + wordsMinusNoninitialVowels[language] + newWord[index+len(patternCompressedAllo):]
                print ':', patternCompressedAllo
            else:
                pattern = respellWithAllophones(wordsMinusNoninitialVowels[language])
                newWord = newWord.replace(pattern, wordsMinusNoninitialVowels[language])
            print ' ->\t', newWord

print "\nnewWord = ", newWord

# put original vowels (& consonants) back in, favouring higher-priority words:
print '\nput original vowels (& consonants) back in, favouring higher-priority words:'
print originalWords
for language in reversed(words.keys()):
    if language != 'Eng':
        if originalWords[language] not in newWord:
            replacer = originalWords[language]
            # types of patterns:  (priorities: original word in allophonic form > compressed word in allophonic form > compressed original word, to enable vowel overwrites)
            patternOrigAllo = respellWithAllophones(originalWords[language])
            patternCompressedAllo = respellWithAllophones(wordsMinusNoninitialVowels[language])
            patternOrigCompressed = wordsMinusNoninitialVowels[language]
            tempWord = newWord
            # check if allophones exist that can be replaced, before checking for replacing compressed original word:
            if patternOrigAllo in respellWithAllophones(newWord):
                print 'replace patternOrigAllo:'
                index = respellWithAllophones(newWord).find(patternOrigAllo)
                newWord = newWord[:index] + replacer + newWord[index+len(patternOrigAllo):]
            elif patternCompressedAllo in respellWithAllophones(newWord):
                print 'replace patternCompressedAllo:'
                index = respellWithAllophones(newWord).find(patternCompressedAllo)
                newWord = newWord[:index] + replacer + newWord[index+len(patternCompressedAllo):]
            else:
                print 'replace patternOrigCompressed:', patternOrigCompressed
                newWord = newWord.replace(patternOrigCompressed, replacer,1)
            print '\t', replacer, '\t->\t', newWord, '<changed>'

print "\nnewWord = ", newWord
print "\noriginal words = "
for language in words:
    if language != 'Eng':
        print language + '\t' + originalWords[language]


text:
layout:     post
title:      "PhotoSphere images as interactive 360° by 180° panoramas"
subtitle:   "It's like pouring a jar of awesome-sauce on panorama images!"
date:       2015-07-28 14:30:00
header-img: 2015-07-28.jpg
header-img-mobile: 2015-07-28_640px.jpg
categories:
  - photography
  - programming
tags:
  - panorama
  - html
  - javascript
---

## TL;DR

### 360° by 180° panoramas made real easy

Here's the result of putting my first full 360° by 180° PhotoSphere photo online as an interactive panorama. Heavy lifting is done by [Google Camera][gcamera] (panorama stitching), [Jérémy Heleine][jh]'s [Photo-Sphere-Viewer][psv] and [Three.js][three.js].

Try grabbing the panorama below and moving left/right/up/down. Also notice that you can animate the view by clicking on the icon at bottom-left:

(Panorama will load here if WebGL is enabled on your browser)

The panorama is a view from outside the [Linnanmäki][lintsi] amusement park's southern entrance in Helsinki, Finland. See the [location on Google Maps][location].

(Panorama will load here if WebGL is enabled on your browser)

The above is a panorama view of the same image that's used on the header of this article!

Please notice that the image *was not actually shot all the way around* (so the source is not a full 360° by 180° panorama) *and hence it looks stretched* and in general a bit off/"wrong".

### Try it yourself with your photos

In case you wanna give it a shot yourself, using your own panorama photos, scroll to the bottom of the article.

## Longer story

### Linnanmäki with niece and nephew

The last time I went to [Linnanmäki][lintsi] to actually go to the amusement rides was exactly two weeks ago. My niece (7y) and nephew (5y) were also there and were thrilled, except for the occasional dissapointments the younger had to face when being too short for some of the rides he would've wanted to catch.

### "Could you get me some Linnanmäki photos?"

I live very close to the amusement park and on a semi-regular basis walk through the area for example before or after going jogging.

A few days ago my niece asked me if I could go and get some photos from Linnanmäki for her so she could use them for example as wallpaper photos on her smartphone. I had forgotten about it and today she asked me about the photos and so I went specifically to take and send photos for her :)

### No panorama?

First off snapping some normal portrait oriented photos and sending them to her as I snapped along; then wanting to take a panorama shot I realized my resently-rooted [OnePlus One][oneplusone] currently running [CyanogenMod 12.1][cm12] (Android 5.1 Lollipop) didn't support panorama...I was a bit confused since previously when running CyanogenMod 11 panoramas were no problem.

### Solution and epiphany

Quick online search later I realized and app called *[Google Camera][gcamera]* existed that I hadn't even heard of even though apparently it's been around for a while already!

On some article I quickly skimmed about the app the writer mentioned the PhotoSphere feature of the app. Having played with manual panorama stitching and creating 360° by 180° panoramas ("full around" panoramas) around the early 2000s I immediately guessed what PhotoSphere would most likely do for me and was more than eager to try it out!

### First go on Google Camera's PhotoSphere

Stitching spherical panoramas back in the day was a whole lot of work. I think I used Paint Shop Pro 4 or something like that at the time. Fast-forward to today and using the PhotoSphere feature I was able to create better-looking panoramas in a matter of minutes while on the go!

Quickly getting the hang of how the PhotoSphere feature of the app worked I walked around the amusement park taking a few more shots, though none of them being full 360° by 180° as that requires almost a few dozen still shots and I didn't wanna stand in one place that long just taking photos.

### Making the panoramas interactive

Right after taking a few of the panoramas with PhotoSphere I thought there's gotta be a JavaScript based interactive viewer for them already, probably on GitHub. A quick online search and guess confirmed.

I used [Jérémy Heleine][jh]'s [Photo-Sphere-Viewer][psv] which is based on [Three.js][three.js] to create the interactive panorama view you saw at the beginning of the article.

## Want to try with your own images right now?

Install [Google Camera][gcamera] on your smartphone, create a PhotoSphere image and then load it here either directly from your phone (if your phone's browser supports WebGL) or alternatively load the created image from your phone to your computer and then here.

<form method="get" action="">
    <input type="file" name="pano" id="panorama-selector" />
</form>

Your panorama image will appear here!

That's all for now :)

[lintsi]: http://www.linnanmaki.fi
[location]: https://www.google.fi/maps/@60.1866079,24.9397097,110m/data=!3m1!1e3
[oneplusone]: https://oneplus.net/one
[cm12]: http://wiki.cyanogenmod.org/w/Install_CM_for_bacon
[gcamera]: https://play.google.com/store/apps/details?id=com.google.android.GoogleCamera
[jh]: http://jeremyheleine.me/#photo-sphere-viewer
[psv]: https://github.com/JeremyHeleine/Photo-Sphere-Viewer
[three.js]: http://threejs.org/


text:
package org.httpmock;

import net.sf.json.JSONObject;
import org.junit.Test;

import java.util.Map;

import static junit.framework.Assert.assertEquals;

public class StubRequestTest {
    @Test
    public void shouldRetrievePath() {
        StubRequest request = requestFrom("{'path': 'test'}");
        assertEquals("test", request.getPath());
    }

    @Test
    public void shouldRetrieveRequestMethod() {
        StubRequest request = requestFrom("{'method': 'POST'}");
        assertEquals("POST", request.getRequestMethod());
    }

    @Test
    public void shouldRetrieveHeaders() {
        StubRequest request = requestFrom("{'headers': {'one': '1', 'two': '2'}}");

        Map<String, String> headers = request.getHeaders();

        assertEquals(2, headers.size());
        assertEquals("1", headers.get("one"));
        assertEquals("2", headers.get("two"));
    }

    @Test
    public void shouldRetrieveBody() {
        StubRequest request = requestFrom("{'body': 'test'}");
        assertEquals("test", request.getBody());
    }

    private StubRequest requestFrom(String json) {
        return new StubRequest(JSONObject.fromObject(json));
    }
}


text:
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using Sinch.ServerSdk.Exceptions;

namespace Sinch.ServerSdk.Callback
{
    public interface ICallbackValidator
    {
        void Validate(string absolutePath, Dictionary<string, string> headers, byte[] body);
    }

    class CallbackValidator : ICallbackValidator
    {
        private readonly string _key;
        private readonly byte[] _secret;

        public CallbackValidator(string key, byte[] secret)
        {
            _key = key;
            _secret = secret;
        }

        public void Validate(string absolutePath, Dictionary<string, string> headers, byte[] body)
        {
            if (!headers.ContainsKey("authorization") || !headers.ContainsKey("x-timestamp") || !headers.ContainsKey("content-type"))
                throw new InvalidCallbackException("Header missing.");

            string[] authorizationSplit = headers["authorization"].Split(' ', ':');
            if (authorizationSplit.Length != 3)
                throw new InvalidCallbackException("Invalid authorization.  Missing or too many authorization header values.");

            if(!authorizationSplit[0].Equals("application", StringComparison.OrdinalIgnoreCase))
                throw new InvalidCallbackException("Invalid authorization type.  Not 'application'");

            var appKeyGuid = ParseAppKey(_key);
            var headerAppKeyGuid = ParseAppKey(authorizationSplit[1]);

            if(!appKeyGuid.Equals(headerAppKeyGuid))
                throw new InvalidCallbackException("Invalid authorization.  Application key in request header is not recognised.");

            using (var sha = new HMACSHA256(_secret))
            {
                var callbackSignature = authorizationSplit[2];
                var signature = Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(BuildStringToSign(absolutePath, headers, body))));

                if ( !signature.Equals(callbackSignature, StringComparison.Ordinal) )
                    throw new InvalidCallbackException("Invalid authorization.  Invalid signing.");
            }
        }

        private static Guid ParseAppKey(string appKeyString)
        {
            Guid appKeyGuid;
            if(!Guid.TryParse(appKeyString, out appKeyGuid))
                throw new InvalidCallbackException("Invalid application key.");
            return appKeyGuid;
        }

        private static string BuildStringToSign(string absolutePath, IReadOnlyDictionary<string, string> headers, byte[] body)
        {
            var sb = new StringBuilder();

            AppendMethod(sb);
            AppendBody(sb, body);
            AppendContentType(sb, headers);
            AppendSinchHeaders(sb, headers);
            AppendPath(sb, absolutePath);

            return sb.ToString();
        }

        private static void AppendPath(StringBuilder sb, string absolutePath)
        {
            sb.Append(absolutePath);
        }

        private static void AppendSinchHeaders(StringBuilder sb, IReadOnlyDictionary<string, string> headers)
        {
            sb.Append("x-timestamp:");
            sb.Append(headers["x-timestamp"]);
            sb.Append("\n");
        }

        private static void AppendContentType(StringBuilder sb, IReadOnlyDictionary<string, string> headers)
        {
            sb.Append(headers["content-type"]);
            sb.Append("\n");
        }

        private static void AppendBody(StringBuilder sb, byte[] body)
        {
            if (body != null)
            {
                using (var md5 = MD5.Create())
                {
                    sb.Append(Convert.ToBase64String(md5.ComputeHash(body)));
                }
            }

            sb.Append("\n");
        }

        private static void AppendMethod(StringBuilder sb)
        {
            sb.Append("POST");
            sb.Append("\n");
        }
    }
}


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
null

#### Original name
Opegrapha grumulosa var. platycarpa Nyl.

### Remarks
null


text:
#ifndef XEON_PHI_MANAGER_SERVICE_H_
#define XEON_PHI_MANAGER_SERVICE_H_

/**
 * \brief   starts Xeon Phi manager service
 *
 * \return  SYS_ERR_OK on succes
 */
errval_t service_start(void);

#endif /* SERVICE_H_ */


text:
<?php

namespace AppBundle\Form\Filter\Admin\Main;

use AppBundle\Filter\Common\Main\NewsletterPageTemplateFilter;
use AppBundle\Form\Filter\Admin\Base\SimpleFilterType;
use Symfony\Component\Form\FormBuilderInterface;

class NewsletterPageTemplateFilterType extends SimpleFilterType {

	protected function addFields(FormBuilderInterface $builder, array $options) {
		parent::addFields($builder, $options);

		$this->addFilterTextField($builder, 'name', 'label.name');
	}

	protected function getEntityType() {
		return NewsletterPageTemplateFilter::class;
	}
}


text:
package net.sourceforge.jwbf.core.contentRep;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;

import java.util.Date;

import net.sourceforge.jwbf.mediawiki.bots.MediaWikiBot;
import org.joda.time.DateTime;
import org.junit.Test;

public class ImmutableArticleTest {

  @Test
  public void testEmptyArticle() {

    // GIVEN
    SimpleArticle simple = new SimpleArticle();
    Article in = new Article(mock(MediaWikiBot.class), simple);

    // WHEN
    ImmutableArticle immutable = ImmutableArticle.copyOf(in);

    // THEN
    assertEquals("", immutable.getEditor());
    assertEquals("", immutable.getEditSummary());
    assertEquals("", immutable.getRevisionId());
    assertEquals("", immutable.getText());
    assertEquals("", immutable.getTitle());
    assertEquals(SimpleArticle.newZeroDate(), immutable.getEditTimestamp());
    assertFalse(immutable.isMinorEdit());
    assertFalse(immutable.isRedirect());
  }

  @Test
  public void testEmptySimpleArticle() {

    // GIVEN
    SimpleArticle in = new SimpleArticle();

    // WHEN
    ImmutableArticle immutable = ImmutableArticle.copyOf(in);

    // THEN
    assertEquals("", immutable.getEditor());
    assertEquals("", immutable.getEditSummary());
    assertEquals("", immutable.getRevisionId());
    assertEquals("", immutable.getText());
    assertEquals("", immutable.getTitle());
    assertEquals(SimpleArticle.newZeroDate(), immutable.getEditTimestamp());
    assertFalse(immutable.isMinorEdit());
    assertFalse(immutable.isRedirect());

  }

  @Test
  public void testSimpleArticle() {

    // GIVEN
    DateTime now = DateTime.now();
    Date nowDate = now.toDate();
    long time = now.getMillis();
    SimpleArticle in = new SimpleArticle();
    in.setEditor("editor");
    in.setEditSummary("summary");
    in.setRevisionId("123");
    in.setText("#redirect a");
    in.setTitle("title");
    in.setEditTimestamp(nowDate);
    in.setMinorEdit(true);

    // WHEN
    ImmutableArticle immutable = ImmutableArticle.copyOf(in);

    // THEN
    nowDate.setTime(SimpleArticle.newZeroDate().getTime());
    assertEquals("editor", immutable.getEditor());
    assertEquals("summary", immutable.getEditSummary());
    assertEquals("123", immutable.getRevisionId());
    assertEquals("#redirect a", immutable.getText());
    assertEquals("title", immutable.getTitle());
    assertEquals(time, immutable.getEditTimestamp().getTime());
    assertTrue(immutable.isMinorEdit());
    assertTrue(immutable.isRedirect());

  }

}


text:
package cass.pure.ioc.handlers.param;

import java.lang.annotation.Annotation;
import java.lang.reflect.Member;

import cass.pure.ioc.AnnotationHandlingException;
import cass.pure.ioc.AutoWire;
import cass.pure.ioc.IOCController;
import cass.pure.ioc.handlers.ParamAnnotationHandler;
import cass.pure.ioc.handlers.ParamHandlerChain;

/**
 * Priority 0.0
 *

 * Default implementation of ParamAnnotationHandler
 *
 simply return the corresponding value of given parameter type.
 * @author wkgcass
 *
 */
public class DefaultParamHandler extends IOCController implements
		ParamAnnotationHandler {

	@Override
	public boolean canHandle(Annotation[] annotations) {
		return true;
	}

	@Override
	public Object handle(Member caller, Class<?> cls, Annotation[] toHandle,
			ParamHandlerChain chain) throws AnnotationHandlingException {
		if(AutoWire.DEBUG_MODE){
		System.out.println(this.getClass().getSimpleName()+"    "+cls);
		}
		try{
			return chain.next().handle(caller, cls, toHandle, chain);
		}catch(AnnotationHandlingException e){}

		if(AutoWire.DEBUG_MODE){
		System.out.println(this.getClass().getSimpleName()+"    start");
		}
		return get(cls);
	}

	@Override
	public double priority() {
		return 0.0;
	}

}


text:
using UnityEngine;
using System.IO;
using System.Collections.Generic;

#if ATC_SUPPORT_ENABLED
using CodeStage.AntiCheat.ObscuredTypes;
#endif

#if UNITY_EDITOR
using UnityEditor;
[InitializeOnLoad]
#endif

public class AndroidNativeSettings : ScriptableObject {

	public const string VERSION_NUMBER = "9.6/19";
	public const string GOOGLE_PLAY_SDK_VERSION_NUMBER = "10.2.1";
	public const string GOOGLE_PLAY_SDK_LEAGCY_VERSION_NUMBER = "10298000";

	public bool EnablePlusAPI 		= true;
	public bool EnableGamesAPI 		= true;
	public bool EnableAppInviteAPI	= true;
	public bool EnableDriveAPI 		= false;
	public bool LoadProfileIcons 	= true;
	public bool LoadProfileImages 	= true;

	public bool LoadQuestsImages 	= true;
	public bool LoadQuestsIcons 	= true;
	public bool LoadEventsIcons 	= true;
	public bool ShowConnectingPopup = true;
	public bool AutoLoadLocalPlayerScore = false;

    //Google Fit
    public bool GoogleFitEnabled = false;

    //ATC:
    public bool EnableATCSupport = false;

	//One Signal
	public bool OneSignalEnabled = false;
	public string OneSignalAppID = "YOUR_ONESIGNAL_APP_ID";
	public string OneSignalDownloadLink = "https://goo.gl/Vc6tfK";
	public string OneSignalDocLink =  "https://goo.gl/aZjkxV";

	//Parce
	public bool UseParsePushNotifications = false;
	public string ParseAppId = "YOUR_PARSE_APP_ID";
	public string DotNetKey = "YOUR_PARSE_DOT_NET_KEY";
	public string ParseDocLink =  "http://goo.gl/9BgQ8r";
	public string ParseDownloadLink =  "https://goo.gl/dm7jYL";

    //PopUps
    public AndroidDialogTheme DialogTheme = AndroidDialogTheme.ThemeDeviceDefaultDark;

	//Soomla
	public bool EnableSoomla = false;
	public string SoomlaDownloadLink = "http://goo.gl/7LYwuj";
	public string SoomlaDocsLink =  "https://goo.gl/es5j1N";
	public string SoomlaGameKey = "" ;
	public string SoomlaEnvKey = "" ;

	//Google AdMob Editor Testing
	public int Ad_EditorFillRateIndex = 4;
	public int Ad_EditorFillRate = 100;
	public bool Is_Ad_EditorTestingEnabled = true;

	//Inn Apps Editor Testing
	public int InApps_EditorFillRateIndex = 4;
	public int InApps_EditorFillRate = 100;
	public bool Is_InApps_EditorTestingEnabled = true;

	//Notifications Editor Testing
	public bool Is_Leaderboards_Editor_Notifications_Enabled = true;
	public bool Is_Achievements_Editor_Notifications_Enabled = true;

	//Google Push
	public string GCM_SenderId = "YOUR_SENDER_ID_HERE";
	public AN_PushNotificationService PushService = AN_PushNotificationService.Google;

	public bool SaveCameraImageToGallery = false;
	public bool UseProductNameAsFolderName = true;
	public string GalleryFolderName = string.Empty;
	public int MaxImageLoadSize = 512;
	public AN_CameraCaptureType CameraCaptureMode;
	public AndroidCameraImageFormat ImageFormat = AndroidCameraImageFormat.JPG;

	public bool ShowAppPermissions = false;
	public bool EnableBillingAPI = true;
	public bool EnablePSAPI = true;
	public bool EnableSocialAPI = true;
	public bool EnableCameraAPI = true;

	public bool ExpandNativeAPI = false;
	public bool ExpandPSAPI = false;
	public bool ExpandBillingAPI = false;
	public bool ExpandSocialAPI = false;
	public bool ExpandCameraAPI = false;

	public bool ThirdPartyParams = false;
	public bool ShowPSSettingsResources = false;
	public bool ShowActions = false;
	public bool GCMSettingsActinve = false;

	//APIs:
	public bool LocalNotificationsAPI = true;
	public bool ImmersiveModeAPI = true;
	public bool ApplicationInformationAPI = true;
	public bool ExternalAppsAPI = true;
	public bool PoupsandPreloadersAPI = true;
	public bool CheckAppLicenseAPI = true;
	public bool NetworkStateAPI = false;
	public bool FirebaseAnalytics = false;

	public bool InAppPurchasesAPI = true;

	public bool GooglePlayServicesAPI = true;
	public bool PlayServicesAdvancedSignInAPI = true;
	public bool GoogleButtonAPI = true;
	public bool AnalyticsAPI = true;
	public bool GoogleCloudSaveAPI = true;
	public bool PushNotificationsAPI = true;
	public bool GoogleMobileAdAPI = true;
	public bool GoogleOAuthAPI = true;

	public bool GalleryAPI = true;
	public bool CameraAPI = true;

	public bool KeepManifestClean = true;

	public string GooglePlayServiceAppID = "0";

	public int ToolbarSelectedIndex = 0;

	#if ATC_SUPPORT_ENABLED
	public  ObscuredString base64EncodedPublicKey = "REPLACE_WITH_YOUR_PUBLIC_KEY";
	#else
	public  string base64EncodedPublicKey = "REPLACE_WITH_YOUR_PUBLIC_KEY";
	#endif

	public bool ShowStoreProducts = true;
	public List<GoogleProductTemplate> InAppProducts = new List<GoogleProductTemplate>();

	public bool ShowLeaderboards = true;
	public List<GPLeaderBoard> Leaderboards = new List<GPLeaderBoard>();

	public bool ShowAchievements = true;
	public List<GPAchievement> Achievements = new List<GPAchievement>();

	public bool ShowWhenAppIsForeground = true;
	public bool EnableVibrationLocal = false;

	public Texture2D LocalNotificationSmallIcon = null;
	public Texture2D LocalNotificationLargeIcon = null;
	public AudioClip LocalNotificationSound = null;
	public int LocalNotificationWakeLockTimer = 10000;

	public bool ReplaceOldNotificationWithNew = false;
	public bool ShowPushWhenAppIsForeground = true;
	public bool EnableVibrationPush = false;

	public Color PushNotificationColor = Color.white;
	public Texture2D PushNotificationSmallIcon = null;
	public Texture2D PushNotificationLargeIcon = null;
	public AudioClip PushNotificationSound = null;

	public const string ANSettingsAssetName = "AndroidNativeSettings";
	public const string ANSettingsAssetExtension = ".asset";

	private static AndroidNativeSettings instance = null;

	public static AndroidNativeSettings Instance {

		get {
			if (instance == null) {
				instance = Resources.Load(ANSettingsAssetName) as AndroidNativeSettings;

				if (instance == null) {

					// If not found, autocreate the asset object.
					instance = CreateInstance<AndroidNativeSettings>();
					#if UNITY_EDITOR
					SA.Common.Util.Files.CreateFolder(SA.Common.Config.SETTINGS_PATH);

					string fullPath = Path.Combine(Path.Combine("Assets", SA.Common.Config.SETTINGS_PATH),
					                               ANSettingsAssetName + ANSettingsAssetExtension
					                               );

					AssetDatabase.CreateAsset(instance, fullPath);
					#endif
				}
			}
			return instance;
		}
	}

	public bool IsBase64KeyWasReplaced {
		get {
			if(base64EncodedPublicKey.Equals("REPLACE_WITH_YOUR_PUBLIC_KEY") || (base64EncodedPublicKey.Equals(""))) {
				return false;
			} else {
				return true;
			}
		}
	}

}


text:
Reports any type parameters and wildcard type arguments explicitly declared to extend java.lang.Object. Such extension is useless as java.lang.Object is supertype of all classes.

Example:

  class ClassA<T extends Object> {}    //reported
  class ClassB<T extends @A Object> {} //depends on setting

  Use the checkbox below to disable inspection in cases of java.lang.Object is annotated.


text:
@implementation XMPPRoster

- (id)initWithStream:(XMPPStream *)aXmppStream
{
	if ((self = [super initWithStream: aXmppStream]))
	{
		wasRosterRequested = NO;
		wasRosterReceived = NO;
	}

	return self;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Roster Management
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (void)addToRoster:(XMPPJID *)jid withName:(NSString *)optionalName
{
	if(jid) {
		XMPPJID *myJID = xmppStream.myJID;

		// Check not re-adding own jid
		if(![[myJID bare] isEqualToString: [jid bare]]) {
			// Build & send IQ roster push stanza
			NSXMLElement *itemElement = [NSXMLElement elementWithName: @"item"];
			[itemElement addAttributeWithName: @"jid" stringValue: [jid bare]];

			if(optionalName) {
				[itemElement addAttributeWithName: @"name" stringValue: optionalName];
			}

			NSXMLElement *queryElement = [NSXMLElement elementWithName: @"query" xmlns: @"jabber:iq:roster"];
			[queryElement addChild: itemElement];

			NSXMLElement *iqStanza = [NSXMLElement elementWithName: @"iq"];
			[iqStanza addAttributeWithName: @"type" stringValue: @"set"];
			[iqStanza addChild: queryElement];

			[xmppStream sendElement: iqStanza];

			// Build & send presence subscribe stanza
			NSXMLElement *presenceStanza = [NSXMLElement elementWithName: @"presence"];
			[presenceStanza addAttributeWithName: @"to" stringValue: [jid bare]];
			[presenceStanza addAttributeWithName: @"type" stringValue: @"subscribe"];

			[xmppStream sendElement: presenceStanza];
		}
	}
}

- (void)removeFromRoster:(XMPPJID *)jid
{
	if(jid) {
		XMPPJID *myJID = xmppStream.myJID;

		// Check not removing own jid
		if(![[myJID bare] isEqualToString: [jid bare]]) {
			// Build & send IQ roster push stanza
			NSXMLElement *itemElement = [NSXMLElement elementWithName: @"item"];
			[itemElement addAttributeWithName: @"jid" stringValue: [jid bare]];
			[itemElement addAttributeWithName: @"subscription" stringValue: @"remove"];

			NSXMLElement *queryElement = [NSXMLElement elementWithName: @"query" xmlns: @"jabber:iq:roster"];
			[queryElement addChild: itemElement];

			NSXMLElement *iqStanza = [NSXMLElement elementWithName:@"iq"];
			[iqStanza addAttributeWithName: @"type" stringValue: @"set"];
			[iqStanza addChild: queryElement];

			[xmppStream sendElement: iqStanza];
		}
	}
}

- (void)setRosterItemName:(NSString *)name forJid:(XMPPJID *)jid
{
	if(jid) {
		// Build & send IQ roster push stanza
		NSXMLElement *itemElement = [NSXMLElement elementWithName: @"item"];
		[itemElement addAttributeWithName: @"jid" stringValue: [jid bare]];
		[itemElement addAttributeWithName: @"name" stringValue: name];

		NSXMLElement *queryElement = [NSXMLElement elementWithName: @"query" xmlns: @"jabber:iq:roster"];
		[queryElement addChild: itemElement];

		NSXMLElement *iqStanza = [NSXMLElement elementWithName: @"iq"];
		[iqStanza addAttributeWithName: @"type" stringValue: @"set"];
		[iqStanza addChild: queryElement];

		[xmppStream sendElement: iqStanza];
	}
}

- (void)acceptPresenceRequest:(XMPPJID *)jid
{
	// Build & send presence response
	NSXMLElement *presenceStanza = [NSXMLElement elementWithName: @"presence"];
	[presenceStanza addAttributeWithName: @"to" stringValue: [jid bare]];
	[presenceStanza addAttributeWithName: @"type" stringValue: @"subscribed"];

	[xmppStream sendElement:presenceStanza];
}

- (void)rejectPresenceRequest:(XMPPJID *)jid
{
	// Build & send presence response
	NSXMLElement *presenceStanza = [NSXMLElement elementWithName: @"presence"];
	[presenceStanza addAttributeWithName: @"to" stringValue: [jid bare]];
	[presenceStanza addAttributeWithName: @"type" stringValue: @"unsubscribed"];

	[xmppStream sendElement: presenceStanza];
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Collection of Roster
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (void)fetchRoster
{
	if (!wasRosterRequested && !wasRosterReceived && [xmppStream isConnected]) {
		// Build & send roster stanza
		NSXMLElement *queryElement = [NSXMLElement elementWithName: @"query" xmlns: @"jabber:iq:roster"];

		NSXMLElement *iqStanza = [NSXMLElement elementWithName: @"iq"];
		[iqStanza addAttributeWithName: @"type" stringValue: @"get"];
		[iqStanza addChild: queryElement];

		[xmppStream sendElement: iqStanza];

		wasRosterRequested = YES;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark XMPPStream Delegate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (void)xmppStreamDidDisconnect:(XMPPStream *)sender
{
	wasRosterRequested = NO;
	wasRosterReceived = NO;
}

- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
	// Note: Some jabber servers send an iq element with an xmlns.
	// Because of the bug in Apple's NSXML (documented in our elementForName method),
	// it is important we specify the xmlns for the query.
	NSString *iqType = [[iq attributeForName: @"type"] stringValue];
	NSXMLElement *queryElement = [iq elementForName: @"query" xmlns: @"jabber:iq:roster"];

	if (queryElement) {
		NSArray *itemElements = [queryElement elementsForName: @"item"];

		// Notify delegates of roster items
		[multicastDelegate xmppRoster: self didReceiveRoster: itemElements isPush: wasRosterReceived];

		if (!wasRosterReceived && [iqType isEqualToString: @"result"]) {
			wasRosterReceived = YES;
		}

		return YES;
	}

	return NO;
}

- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
	// Notify delegates of incoming presence
	[multicastDelegate xmppRoster: self didReceivePresence: presence];
}

@end


text:
title: "Sorry, Wrong Number"
playwright: Lucille Fletcher
period: Autumn
season: Fringe
season_sort: 45
date_start: 2013-11-04
date_end: 2013-11-05
venue: New Theatre Studio A

cast:
  - role: Mrs Stevenson
    name: Becca Clee
  - role: Sergeant Duffy
    name: Ollie Shortt
  - role: Operator
    name: Lucy Kerr
  - role: George / Western Union
    name: Nick Lowe
  - role: Chief Operator / Information
    name: Emily Sterling
  - role: Man / Hospital Receptionist
    name: Ben Hollands

crew:
  - role: Director
    name: Alice Hildreth
  - role: Producer
    name: Matthew Richards
  - role: Set Designer
    name: Matthew Richards
  - role: Set Designer
    name: Alice Hildreth
  - role: Stage Manager
    name: Holly Pownall
  - role: Technical Director
    name: Nathan
  - role: Lighting Designer
    name: Nathan
  - role: Sound Designer
    name: Joseph Heil
  - role: Technical Operator
    name: Holly Pownall
  - role: Technical Operator
    name: Nathan
  - role: Publicity Designer
    name: Ben Hollands
  - role: Photographer
    name: Thomas Addison

assets:
  - type: poster
    image: 5TktvjZ

links:
  - type: Review
    href: https://impactnottingham.com/2013/11/sorry-wrong-number-the-nottingham-new-theatre/
    snapshot: awjCr
    publisher: Impact Nottingham
    author: Eleanor Hughes
    title: "Sorry, Wrong Number @ Nottingham New Theatre"
    date: 2013-11-05
    rating: 4/5
    quote: "A night of intrigue and suspense,  director Alice Hildreth starts Nottingham New Theatre's fringe season off with a bang."
---
Mrs Stevenson is home all alone, unable to leave her bed, trying to get hold of her husband. Instead of hearing his comforting voice, she hears a murder plot. Armed with only a telephone she must race against time to stop a murder that affects her more than she knows...


text:
package com.budiyev.android.imageloader;

import java.io.File;

import androidx.annotation.NonNull;

final class FileDataDescriptorFactory implements DataDescriptorFactory<File> {
    @NonNull
    @Override
    public DataDescriptor<File> newDescriptor(@NonNull final File data) {
        return new FileDataDescriptor(data);
    }
}


text:
package org.drools.benchmarks.turtle.buildtime;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.infra.Blackhole;

/**
 * Time how long it takes to create knowledge base from rules saved in DRL files.
 */
public class BuildDRLWithoutKieBaseBenchmark extends AbstractBuildtimeBenchmark {

    @Param({"5k", "10k"})
    private String nrOfRules;

    @Setup
    public void addResources() {
        addClassPathResource("kbase-creation/drl-kbase-creation-" + nrOfRules + ".drl");
        createKieFileSystemFromResources();
    }

    @Benchmark
    public void timeKBaseCreationFromDrl(final Blackhole eater) {
        buildResourcesWithoutKieBase(eater);
    }

}


text:
<!DOCTYPE html>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />

    <title>rocLv's home for ruby & rails - All about ruby and rails</title>
    <meta name="description" content="ruby or rails news, or some site developing stuff" />

    <meta name="HandheldFriendly" content="True" />
    <meta name="MobileOptimized" content="320" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="stylesheet" type="text/css" href="/assets/css/screen.css" />
    <link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Merriweather:300,700,700italic,300italic|Open+Sans:700,400" />

    <link rel="stylesheet" type="text/css" href="/assets/css/main.css" />

        Home
        Subscribe

Ruby中定义类方法的八种方法

                <time class="post-date" datetime="2015-09-02">02 Sep 2015</time>

Ruby中定义类的六种方法

众所周知,Ruby中的所有均为对象。Class是继承Object,而Object是继承BasicObject。

在Ruby中可以为特定的对象定义专属于这个对象的方法,名为单例方法。如:

"by str = 'singleton method'

class « str def hello puts "I'm a singleton method" end end

str.hello

I'm a singleton method

"于类Class继承于Object ,所以Class本身也是对象。这样,我们可以把为类添加类方法,当作为对象Class添加单例方法。

"by class C class « C def singleton_method puts "I'm one of Class C's methods" end end end

C.singleton_method

I'm one of Class C's methods

"于在类定义中,self为类本身,因此,如果在类中定义类方法,可以用self替代类名,因此衍生出第二种定义类的方法:

"by class C class « self

  def singleton_method
      puts 'I am one of Class methods'
  end

end end

"

Martz在设计Ruby的时候,把所有程序员设想为合格的程序员,因此,他要程序员为自己所写的代码负责,而不是通过提供受限的编程语言,保证程序员所写的代码质量。所以,由于上面的那种写法不太符合程序员的习惯,因此提供了以下简便一点的方法:

"by class C def C.class_method puts 'another way to define class methods' end end

"样,使用self来替换类名得到第四种声明类方法的方法:

"by class C def self.class_method puts 'use self to replace class name' end end

"此为止,其实类声明的方法就可以结束了。但是本则孔乙己(90s、00s等没学过这篇文章的需要脑补一下了)的精神胜利法,我再提供另外两种。 因为以上声明类方法的方式中,有两种是可以放在类外部声明的,所以又有了另外两种声明类的方法(lol):

"by class C end

class « C def singleton_method puts 'the fifth way to define class methods' end end

def C.singletom_method puts 'the sixth way to define class methods' end

"合以上,终于拼凑够了"回"字的六种写法。

除了定义类方法,我们可以用以下方法,把任何类变成单例类:

"by

Object本身也是类,(类又继承Object,能不这么虐人吗?)所以打开类Object,为Object添加单例方法:

class Object class « self self end end

"

大神why the lucky stiff依据这个,为元编程创建了Metaid库:

"by class Object #将类变为单例类 def metaclass; class « self; self; end; end #看上去是实例方法,其实是类方法 def meta_eval &blk; metaclass.instance_eval &blk; end

# 定义类方法 def meta_def name, &blk mate_eval { define_method name, &blk } end

#定义类的实例方法 def class_def name, &blk class_eval { define_method name, &blk } end

end

"用上述库,定义类方法:

"by class C end

C.meta_def class_method_name { #方法 }

"

最后,还有一种:

"by class C end

C.define_singleton_method(:single_method_name) do puts 'the eighth method' end

"

如此说来,共有7种定义类的方法了。

                    rocLv's Picture

 rocLv

                        I'm a common rubyist, feel free to connect with me.

            <form action="https://shenghuo.alipay.com/send/payment/fill.htm" method="POST" target="_blank" accept-charset="GBK">

       <input name="optEmail" type="hidden" value="roc_war@yahoo.com.cn" />

       <input name="payAmount" type="hidden" value="5" />

       <input id="title" name="title" type="hidden" value="付款说明" />

       <input name="memo" type="hidden" value="备注" />

       <input name="pay" type="image" value="打赏" src= '/assets/images/donate.png' />

      </form>

    Please enable JavaScript to view the comments powered by Disqus.
    comments powered by Disqus

        rocLv's home for ruby & rails ©
               • All rights reserved.

Made with Jekyll using
        Kasper theme


text:
using System;
using System.Collections.Generic;
using System.IO;

namespace Lansweeper6_PasswordRecovery
{
    class PasswordRecovery
    {
        private string KeyFilename;
        private string CipherFilename;
        private byte[] Key;
        private Dictionary<string, string> Credentials;
        private CryptoClass Crypto;

        public PasswordRecovery(string keyFilename, string cipherFilename)
        {
            KeyFilename = keyFilename;
            CipherFilename = cipherFilename;
            Key = new byte[1024];
            Credentials = new Dictionary<string, string>();
            Crypto = null;
        }

        public bool LoadFiles()
        {
            bool res = true;
            if (KeyFilename == null || CipherFilename == null)
                return res;

            Console.WriteLine(string.Format("[*] Loading key file {0}.", KeyFilename));
            Key = File.ReadAllBytes(KeyFilename);
            Console.WriteLine(string.Format("[*] Processing {0} bytes for the key file.", Key.Length));
            if (Key != null && Key.Length > 0)
                Crypto = new CryptoClass(Key);
            /*
             * Cipher File should consist of user:password delimited by comma.
             * Passwords should be base64 encoded.
             * Credentials should be one per line.
             */
            Console.WriteLine(string.Format("[*] Loading cipher file {0}", CipherFilename));
            foreach (string s in File.ReadAllLines(CipherFilename))
            {
                Console.WriteLine(string.Format("[*] Loading cipher line {0}", s));
                Credentials.Add(s.Split(':')[0],
                    s.Split(':')[1]);
            }
            res = false;
            return res;
        }

        public void DecryptAll()
        {
            if (Crypto == null)
            {
                Console.WriteLine("[x] Error processing the key file...quit.");
                return;
            }

            string password;

            foreach(KeyValuePair<string, string> kv in Credentials)
            {
                password = "";
                password = kv.Value;

                Console.WriteLine(string.Format("[-] Recovered password for user {0} as {1}",
                    kv.Key,
                    Crypto.Decrypt(kv.Value)
                    ));
            }
        }

    }
}


text:
package router

import (
	"net/http"

	"github.com/zpatrick/fireball"
)

func NewRouter(routes []*fireball.Route, doProxy fireball.Handler) fireball.RouterFunc {
	router := fireball.NewBasicRouter(routes)
	return fireball.RouterFunc(func(req *http.Request) (*fireball.RouteMatch, error) {
		match, err := router.Match(req)
		if match != nil || err != nil {
			return match, err
		}

		// perform reverse proxy on any request that doesn't match the d.ims.io api
		// this could be improved by verifying the request is part of the registry api
		// see: https://docs.docker.com/registry/spec/api
		return &fireball.RouteMatch{Handler: doProxy}, nil
	})
}


text:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;

using ExcelFile.net;

using Ioc.Net.Model.Models;

namespace Ioc.Net.Model.Services
{
    // 注意: 使用"重构"菜单上的"重命名"命令,可以同时更改代码、svc 和配置文件中的类名"UserService"。
    // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 UserService.svc 或 UserService.svc.cs,然后开始调试。
    public class UserService : BaseService, IUserService
    {
        public User[] GetUsers()
        {
            if (!HasCache<User[]>("users"))
            {
                SetCache("users", Entities.Users.ToArray(), new TimeSpan(0, 20, 0));
            }
            return GetCache<User[]>("users");
        }

        public IQueryable<User> GetUsers<T>(out int count, int skipped = 0, bool isAsc = true, Expression<Func<User, T>> order = null, params Expression<Func<User, bool>>[] conditions)
        {
            IQueryable<User> query = Entities.Users;
            foreach (var condition in conditions)
            {
                query = query.Where(condition);
            }
            count = query.Count();
            if (order == null)
            {
                query = query.OrderBy(u => u.ID);
            }
            else if (isAsc)
            {
                query = query.OrderBy(order);
            }
            else
            {
                query = query.OrderByDescending(order);
            }
            return query.Skip(skipped).Take(10);
        }

        public void Export(User[] users)
        {
            var excel = new ExcelEditor("/Templates/Users.xlsx");
            excel.Set("users", users);
            ExportExcel(excel, string.Format("Users {0}.xlsx", DateTime.Now.ToString("yyyyMMddHHmmss")));
        }

        public List<User> Import(string fileName)
        {
            var result = new List<User>();
            var path = GetPath("~/UploadedFiles/" + fileName);
            foreach (var sheet in ExcelUtils.New(path, FileMode.Open, FileAccess.Read).AsEnumerable())
            {
                for (var i = 1; i < sheet.LastRowNum; i++)
                {
                    var row = sheet.GetRow(i);
                    if (row == null)
                    {
                        continue;
                    }
                    result.Add(new User
                               {
                                   ID = (int) row.GetCell(0).GetNumber(),
                                   Name = row.GetCell(1).GetString()
                               });
                }
            }
            return result;
        }

        public void AddUser(User user)
        {
            Entities.Users.Add(user);
        }
    }
}


text:
import {Builder} from './builder.dto';
import {IHrefValue} from './hrefValue.dto';
import {IRoleAttributeName, RoleAttributeName} from './roleAttributeName.dto';

export interface IRoleAttribute {
    value: string[];
    attributeName: IHrefValue<IRoleAttributeName>;
}

export class RoleAttribute implements IRoleAttribute {
    public static build(sourceObject: any): IRoleAttribute {
        return new Builder<IRoleAttribute>(sourceObject, this)
            .mapHref('attributeName', RoleAttributeName)
            .build();
    }

    constructor(public value: string[],
                public attributeName: IHrefValue<IRoleAttributeName>) {
    }
}


text:
using DotNetBlog.Core.Entity;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace DotNetBlog.Core.Data.Mappings
{
    public sealed class PageMapping
    {
        public static void Map(EntityTypeBuilder<Page> builder)
        {
            builder.ToTable("Page");

            builder.HasKey(t => t.ID);

            builder.HasIndex(t => t.Alias).IsUnique();

            builder.Property(t => t.ID).ValueGeneratedOnAdd().UseSqlServerIdentityColumn();
            builder.Property(t => t.Title).IsRequired().HasMaxLength(100);
            builder.Property(t => t.Alias).HasMaxLength(100);
            builder.Property(t => t.Keywords).HasMaxLength(100);
            builder.Property(t => t.Description).HasMaxLength(500);
        }
    }
}


text:
name             'perf_testing'
maintainer       'YOUR_NAME'
maintainer_email 'YOUR_EMAIL'
license          'All rights reserved'
description      'Installs/Configures perf_testing'
long_description 'Installs/Configures perf_testing'
version          '0.1.0'
depends          'build-essential'
depends          'collectd'
depends          'collectd_plugins'


text:
using Gedcomx.Model;
using Gx.Links;
using Newtonsoft.Json;
// <auto-generated>
//
//
// Generated by Enunciate.
// </auto-generated>
using System;
using System.Collections.Generic;
using System.Linq;
using Gedcomx.Model.Util;

namespace Gx.Atom
{

    /// <remarks>
    ///  <p>The Atom data formats provide a format for web content and metadata syndication. The XML media type is defined by
    ///  <a href="http://tools.ietf.org/html/rfc4287#section-4">RFC 4287</a>. The JSON data format is specific to GEDCOM X and is a
    ///  translation to JSON from the XML.</p>
    /// </remarks>
    ///
    ///  <p>The Atom data formats provide a format for web content and metadata syndication. The XML media type is defined by
    ///  <a href="http://tools.ietf.org/html/rfc4287#section-4">RFC 4287</a>. The JSON data format is specific to GEDCOM X and is a
    ///  translation to JSON from the XML.</p>
    ///
    [System.SerializableAttribute()]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.w3.org/2005/Atom", TypeName = "Feed")]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.w3.org/2005/Atom", ElementName = "feed")]
    public partial class Feed : Gx.Atom.ExtensibleElement, ISupportsLinks
    {

        private System.Collections.Generic.List<Gx.Atom.Person> _authors;
        private System.Collections.Generic.List<Gx.Atom.Person> _contributors;
        private Gx.Atom.Generator _generator;
        private string _icon;
        private string _id;
        private int? _results;
        private bool _resultsSpecified;
        private int? _index;
        private bool _indexSpecified;
        private System.Collections.Generic.List<Gx.Links.Link> _links;
        private string _logo;
        private string _rights;
        private string _subtitle;
        private string _title;
        private DateTime? _updated;
        private bool _updatedSpecified;
        private System.Collections.Generic.List<Gx.Atom.Entry> _entries;
        private System.Collections.Generic.List<Gx.Records.Field> _facets;
        ///
        ///  The author of the feed.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "author", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("authors")]
        public System.Collections.Generic.List<Gx.Atom.Person> Authors
        {
            get
            {
                return this._authors;
            }
            set
            {
                this._authors = value;
            }
        }
        ///
        ///  information about a category associated with the feed
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "contributor", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("contributors")]
        public System.Collections.Generic.List<Gx.Atom.Person> Contributors
        {
            get
            {
                return this._contributors;
            }
            set
            {
                this._contributors = value;
            }
        }
        ///
        ///  identifies the agent used to generate the feed
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "generator", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("generator")]
        public Gx.Atom.Generator Generator
        {
            get
            {
                return this._generator;
            }
            set
            {
                this._generator = value;
            }
        }
        ///
        ///  identifies an image that provides iconic visual identification for the feed.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "icon", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("icon")]
        public string Icon
        {
            get
            {
                return this._icon;
            }
            set
            {
                this._icon = value;
            }
        }
        ///
        ///  a permanent, universally unique identifier for the feed.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "id", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("id")]
        public string Id
        {
            get
            {
                return this._id;
            }
            set
            {
                this._id = value;
            }
        }
        ///
        ///  The total number of results available, if this feed is supplying a subset of results, such as for a query.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "results", Namespace = "http://gedcomx.org/v1/")]
        [Newtonsoft.Json.JsonProperty("results")]
        public int Results
        {
            get
            {
                return this._results.GetValueOrDefault();
            }
            set
            {
                this._results = value;
                this._resultsSpecified = true;
            }
        }

        ///
        ///  Property for the XML serializer indicating whether the "Results" property should be included in the output.
        ///
        [System.Xml.Serialization.XmlIgnoreAttribute]
        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
        [Newtonsoft.Json.JsonIgnore]
        public bool ResultsSpecified
        {
            get
            {
                return this._resultsSpecified;
            }
            set
            {
                this._resultsSpecified = value;
            }
        }

        ///
        ///  The index of the first entry in this page of data, if this feed is supplying a page of data.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "index", Namespace = "http://gedcomx.org/v1/")]
        [Newtonsoft.Json.JsonProperty("index")]
        public int Index
        {
            get
            {
                return this._index.GetValueOrDefault();
            }
            set
            {
                this._index = value;
                this._indexSpecified = true;
            }
        }

        ///
        ///  Property for the XML serializer indicating whether the "Index" property should be included in the output.
        ///
        [System.Xml.Serialization.XmlIgnoreAttribute]
        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
        [Newtonsoft.Json.JsonIgnore]
        public bool IndexSpecified
        {
            get
            {
                return this._indexSpecified;
            }
            set
            {
                this._indexSpecified = value;
            }
        }

        ///
        ///  a reference from a feed to a Web resource.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "link", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("links")]
        [JsonConverter(typeof(JsonHypermediaLinksConverter))]
        public System.Collections.Generic.List<Gx.Links.Link> Links
        {
            get
            {
                return this._links;
            }
            set
            {
                this._links = value;
            }
        }
        ///
        ///  identifies an image that provides visual identification for the feed.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "logo", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("logo")]
        public string Logo
        {
            get
            {
                return this._logo;
            }
            set
            {
                this._logo = value;
            }
        }
        ///
        ///  information about rights held in and over the feed.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "rights", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("rights")]
        public string Rights
        {
            get
            {
                return this._rights;
            }
            set
            {
                this._rights = value;
            }
        }
        ///
        ///  a human-readable description or subtitle for the feed.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "subtitle", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("subtitle")]
        public string Subtitle
        {
            get
            {
                return this._subtitle;
            }
            set
            {
                this._subtitle = value;
            }
        }
        ///
        ///  a human-readable title for the feed
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "title", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("title")]
        public string Title
        {
            get
            {
                return this._title;
            }
            set
            {
                this._title = value;
            }
        }
        ///
        ///  the most recent instant in time when the feed was modified in a way the publisher considers significant.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "updated", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("updated")]
        [JsonConverter(typeof(JsonUnixTimestampConverter))]
        public DateTime Updated
        {
            get
            {
                return this._updated.GetValueOrDefault();
            }
            set
            {
                this._updated = value;
                this._updatedSpecified = true;
            }
        }

        ///
        ///  Property for the XML serializer indicating whether the "Updated" property should be included in the output.
        ///
        [System.Xml.Serialization.XmlIgnoreAttribute]
        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
        [Newtonsoft.Json.JsonIgnore]
        public bool UpdatedSpecified
        {
            get
            {
                return this._updatedSpecified;
            }
            set
            {
                this._updatedSpecified = value;
            }
        }

        ///
        ///  The entries in the feed.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "entry", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("entries")]
        public System.Collections.Generic.List<Gx.Atom.Entry> Entries
        {
            get
            {
                return this._entries;
            }
            set
            {
                this._entries = value;
            }
        }
        ///
        ///  The list of facets for the feed, used for convenience in browsing and filtering.
        ///
        [System.Xml.Serialization.XmlElementAttribute(ElementName = "facet", Namespace = "http://www.w3.org/2005/Atom")]
        [Newtonsoft.Json.JsonProperty("facets")]
        public System.Collections.Generic.List<Gx.Records.Field> Facets
        {
            get
            {
                return this._facets;
            }
            set
            {
                this._facets = value;
            }
        }

        ///
        /// Add a hypermedia link. Links are not specified by GEDCOM X core, but as extension elements by GEDCOM X RS.
        ///
        /// <param name="link">The hypermedia link. Links are not specified by GEDCOM X core, but as extension elements by GEDCOM X RS.</param>
        public void AddLink(Link link)
        {
            if (this._links == null)
            {
                _links = new List<Link>();
            }

            this._links.Add(link);
        }

        ///
        /// Add a hypermedia link.
        ///
        /// <param name="rel">The link rel.</param>
        /// <param name="href">The target URI.</param>
        public void AddLink(String rel, Uri href)
        {
            AddLink(new Link(rel, href.ToString()));
        }

        ///
        /// Add a templated link.
        ///
        /// <param name="rel">The link rel.</param>
        /// <param name="template">The link template.</param>
        public void AddTemplatedLink(String rel, String template)
        {
            Link link = new Link();
            link.Rel = rel;
            link.Template = template;
            AddLink(link);
        }

        ///
        /// Get a link by its rel. Links are not specified by GEDCOM X core, but as extension elements by GEDCOM X RS.
        ///
        /// <param name="rel">The link rel.</param>
        /// <returns>
        /// The link by rel.
        /// </returns>
        public Link GetLink(string rel)
        {
            return GetLinks(rel).FirstOrDefault();
        }

        ///
        /// Get a list of links by rel. Links are not specified by GEDCOM X core, but as extension elements by GEDCOM X RS.
        ///
        /// <param name="rel">The links by rel.</param>
        /// <returns></returns>
        public List<Link> GetLinks(string rel)
        {
            return this.Links.Where(x => x.Rel == rel).ToList();
        }
    }
}


text:
// notice_start

// notice_end

import espReact from '../src/index';
import {
    RouterProvider,
    SmartComponent,
    ViewBinder,
    viewBinding,
    ModelSelector,
    shouldUpdateMixin
} from '../src/index';

describe('index exports', () => {
    it('should export RouterProvider', () => {
        expect(espReact.RouterProvider).toBeDefined();
        expect(RouterProvider).toBeDefined();
    });

    it('should export SmartComponent', () => {
        expect(espReact.SmartComponent).toBeDefined();
        expect(SmartComponent).toBeDefined();
    });

    it('should export ViewBinder', () => {
        expect(espReact.ViewBinder).toBeDefined();
        expect(ViewBinder).toBeDefined();
    });

    it('should export viewBinding', () => {
        expect(espReact.viewBinding).toBeDefined();
        expect(viewBinding).toBeDefined();
    });

    it('should export ModelSelector', () => {
        expect(espReact.ModelSelector).toBeDefined();
        expect(ModelSelector).toBeDefined();
    });

    it('should export shouldUpdateMixin', () => {
        expect(espReact.shouldUpdateMixin).toBeDefined();
        expect(shouldUpdateMixin).toBeDefined();
    });
});