text:
from twisted.lore import tree, process
from twisted.web import domhelpers, microdom
from twisted.python import reflect

import parser, urlparse, os.path

# parser.suite in Python 2.3 raises SyntaxError, <2.3 raises parser.ParserError
parserErrors = (SyntaxError, parser.ParserError)

class TagChecker:

    def check(self, dom, filename):
        self.hadErrors = 0
        for method in reflect.prefixedMethods(self, 'check_'):
            method(dom, filename)
        if self.hadErrors:
            raise process.ProcessingFailure("invalid format")

    def _reportError(self, filename, element, error):
        hlint = element.hasAttribute('hlint') and element.getAttribute('hlint')
        if hlint != 'off':
            self.hadErrors = 1
            pos = getattr(element, '_markpos', None) or (0, 0)
            print "%s:%s:%s: %s" % ((filename,)+pos+(error,))

class DefaultTagChecker(TagChecker):

    def __init__(self, allowedTags, allowedClasses):
        self.allowedTags = allowedTags
        self.allowedClasses = allowedClasses

    def check_disallowedElements(self, dom, filename):
        def m(node, self=self):
            return not self.allowedTags(node.tagName)
        for element in domhelpers.findElements(dom, m):
            self._reportError(filename, element,
                               'unrecommended tag %s' % element.tagName)

    def check_disallowedClasses(self, dom, filename):
        def matcher(element, self=self):
            if not element.hasAttribute('class'):
                return 0
            checker = self.allowedClasses.get(element.tagName, lambda x:0)
            return not checker(element.getAttribute('class'))
        for element in domhelpers.findElements(dom, matcher):
            self._reportError(filename, element,
                              'unknown class %s' %element.getAttribute('class'))

    def check_quote(self, dom, filename):
        def matcher(node):
            return ('"' in getattr(node, 'data', '') and
                    not isinstance(node, microdom.Comment) and
                    not  [1 for n in domhelpers.getParents(node)[1:-1]
                           if n.tagName in ('pre', 'code')])
        for node in domhelpers.findNodes(dom, matcher):
            self._reportError(filename, node.parentNode, 'contains quote')

    def check_styleattr(self, dom, filename):
        for node in domhelpers.findElementsWithAttribute(dom, 'style'):
            self._reportError(filename, node, 'explicit style')

    def check_align(self, dom, filename):
        for node in domhelpers.findElementsWithAttribute(dom, 'align'):
            self._reportError(filename, node, 'explicit alignment')

    def check_style(self, dom, filename):
        for node in domhelpers.findNodesNamed(dom, 'style'):
            if domhelpers.getNodeText(node) != '':
                self._reportError(filename, node, 'hand hacked style')

    def check_title(self, dom, filename):
        doc = dom.documentElement
        title = domhelpers.findNodesNamed(dom, 'title')
        if len(title)!=1:
            return self._reportError(filename, doc, 'not exactly one title')
        h1 = domhelpers.findNodesNamed(dom, 'h1')
        if len(h1)!=1:
            return self._reportError(filename, doc, 'not exactly one h1')
        if domhelpers.getNodeText(h1[0]) != domhelpers.getNodeText(title[0]):
            self._reportError(filename, h1[0], 'title and h1 text differ')

    def check_80_columns(self, dom, filename):
        for node in domhelpers.findNodesNamed(dom, 'pre'):
            # the ps/pdf output is in a font that cuts off at 80 characters,
            # so this is enforced to make sure the interesting parts (which
            # are likely to be on the right-hand edge) stay on the printed
            # page.
            for line in domhelpers.gatherTextNodes(node, 1).split('\n'):
                if len(line.rstrip()) > 80:
                    self._reportError(filename, node,
                                      'text wider than 80 columns in pre')
        for node in domhelpers.findNodesNamed(dom, 'a'):
            if node.getAttribute('class', '').endswith('listing'):
                try:
                    fn = os.path.dirname(filename)
                    fn = os.path.join(fn, node.getAttribute('href'))
                    lines = open(fn,'r').readlines()
                except:
                    self._reportError(filename, node,
                                      'bad listing href: %r' %
                                      node.getAttribute('href'))
                    continue

                for line in lines:
                    if len(line.rstrip()) > 80:
                        self._reportError(filename, node,
                                          'listing wider than 80 columns')

    def check_pre_py_listing(self, dom, filename):
        for node in domhelpers.findNodesNamed(dom, 'pre'):
            if node.getAttribute('class') == 'python':
                try:
                    text = domhelpers.getNodeText(node)
                    # Fix < and >
                    text = text.replace('>', '>').replace('<', '<')
                    # Strip blank lines
                    lines = filter(None,[l.rstrip() for l in text.split('\n')])
                    # Strip leading space
                    while not [1 for line in lines if line[:1] not in ('',' ')]:
                        lines = [line[1:] for line in lines]
                    text = '\n'.join(lines) + '\n'
                    try:
                        parser.suite(text)
                    except parserErrors, e:
                        # Pretend the "..." idiom is syntactically valid
                        text = text.replace("...","'...'")
                        parser.suite(text)
                except parserErrors, e:
                    self._reportError(filename, node,
                                      'invalid python code:' + str(e))

    def check_anchor_in_heading(self, dom, filename):
        headingNames = ['h%d' % n for n in range(1,7)]
        for hname in headingNames:
            for node in domhelpers.findNodesNamed(dom, hname):
                if domhelpers.findNodesNamed(node, 'a'):
                    self._reportError(filename, node, 'anchor in heading')

    def check_texturl_matches_href(self, dom, filename):
        for node in domhelpers.findNodesNamed(dom, 'a'):
            if not node.hasAttribute('href'):
                continue
            text = domhelpers.getNodeText(node)
            proto = urlparse.urlparse(text)[0]
            if proto and ' ' not in text:
                if text != node.getAttribute('href',''):
                    self._reportError(filename, node,
                                      'link text does not match href')

    def check_a_py_listing(self, dom, filename):
        for node in domhelpers.findNodesNamed(dom, 'a'):
            if node.getAttribute('class') == 'py-listing':
                fn = os.path.join(os.path.dirname(filename),
                                  node.getAttribute('href'))
                lines = open(fn).readlines()
                lines = lines[int(node.getAttribute('skipLines', 0)):]
                for line, num in zip(lines, range(len(lines))):
                    if line.count('59 Temple Place, Suite 330, Boston'):
                        self._reportError(filename, node,
                            'included source file %s has licence boilerplate.'
                            '  Use skipLines="%d".'
                            % (fn, int(node.getAttribute('skipLines',0))+num+1))

    def check_lists(self, dom, filename):
        for node in (domhelpers.findNodesNamed(dom, 'ul')+
                     domhelpers.findNodesNamed(dom, 'ol')):
            if not node.childNodes:
                self._reportError(filename, node, 'empty list')
            for child in node.childNodes:
                if child.nodeName != 'li':
                    self._reportError(filename, node,
                                      'only list items allowed in lists')

def list2dict(l):
    d = {}
    for el in l:
        d[el] = None
    return d

classes = list2dict(['shell', 'API', 'python', 'py-prototype', 'py-filename',
                     'py-src-string', 'py-signature', 'py-src-parameter',
                     'py-src-identifier', 'py-src-keyword'])

tags = list2dict(["html", "title", "head", "body", "h1", "h2", "h3", "ol", "ul",
                  "dl", "li", "dt", "dd", "p", "code", "img", "blockquote", "a",
                  "cite", "div", "span", "strong", "em", "pre", "q", "table",
                  "tr", "td", "th", "style", "sub", "sup", "link"])

span = list2dict(['footnote', 'manhole-output', 'index'])

div = list2dict(['note', 'boxed', 'doit'])

a = list2dict(['listing', 'py-listing', 'html-listing', 'absolute'])

pre = list2dict(['python', 'shell', 'python-interpreter', 'elisp'])

allowed = {'code': classes.has_key, 'span': span.has_key, 'div': div.has_key,
           'a': a.has_key, 'pre': pre.has_key, 'ul': lambda x: x=='toc',
           'ol': lambda x: x=='toc', 'li': lambda x: x=='ignoretoc'}

def getDefaultChecker():
    return DefaultTagChecker(tags.has_key, allowed)

def doFile(file, checker):
    dom = tree.parseFileAndReport(file)
    if dom:
        checker.check(dom, file)


text:
var
  assert = require('assert'),
  path   = require('path'),
  exec   = require('child_process').exec,
  tmp    = require('../lib/tmp');

// make sure that we do not test spam the global tmp
tmp.TMP_DIR = './tmp';

function _spawnTestWithError(testFile, params, cb) {
  _spawnTest(true, testFile, params, cb);
}

function _spawnTestWithoutError(testFile, params, cb) {
  _spawnTest(false, testFile, params, cb);
}

function _spawnTest(passError, testFile, params, cb) {
  var
    node_path = process.argv[0],
    command = [ node_path, path.join(__dirname, testFile) ].concat(params).join(' ');

  exec(command, function _execDone(err, stdout, stderr) {
    if (passError) {
      if (err) {
        return cb(err);
      } else if (stderr.length > 0) {
        return cb(stderr.toString());
      }
    }

    return cb(null, stdout.toString());
  });
}

function _testStat(stat, mode) {
  assert.equal(stat.uid, process.getuid(), 'should have the same UID');
  assert.equal(stat.gid, process.getgid(), 'should have the same GUID');
  assert.equal(stat.mode, mode);
}

function _testPrefix(prefix) {
  return function _testPrefixGenerated(err, name) {
    assert.equal(path.basename(name).slice(0, prefix.length), prefix, 'should have the provided prefix');
  };
}

function _testPrefixSync(prefix) {
  return function _testPrefixGeneratedSync(result) {
    if (result instanceof Error) {
      throw result;
    }
    _testPrefix(prefix)(null, result.name, result.fd);
  };
}

function _testPostfix(postfix) {
  return function _testPostfixGenerated(err, name) {
    assert.equal(name.slice(name.length - postfix.length, name.length), postfix, 'should have the provided postfix');
  };
}

function _testPostfixSync(postfix) {
  return function _testPostfixGeneratedSync(result) {
    if (result instanceof Error) {
      throw result;
    }
    _testPostfix(postfix)(null, result.name, result.fd);
  };
}

function _testKeep(type, keep, cb) {
  _spawnTestWithError('keep.js', [ type, keep ], cb);
}

function _testKeepSync(type, keep, cb) {
  _spawnTestWithError('keep-sync.js', [ type, keep ], cb);
}

function _testGraceful(type, graceful, cb) {
  _spawnTestWithoutError('graceful.js', [ type, graceful ], cb);
}

function _testGracefulSync(type, graceful, cb) {
  _spawnTestWithoutError('graceful-sync.js', [ type, graceful ], cb);
}

function _assertName(err, name) {
  assert.isString(name);
  assert.isNotZero(name.length);
}

function _assertNameSync(result) {
  if (result instanceof Error) {
    throw result;
  }
  var name = typeof(result) == 'string' ? result : result.name;
  _assertName(null, name);
}

function _testName(expected){
  return function _testNameGenerated(err, name) {
    assert.equal(expected, name, 'should have the provided name');
  };
}

function _testNameSync(expected){
  return function _testNameGeneratedSync(result) {
    if (result instanceof Error) {
      throw result;
    }
    _testName(expected)(null, result.name, result.fd);
  };
}

function _testUnsafeCleanup(unsafe, cb) {
  _spawnTestWithoutError('unsafe.js', [ 'dir', unsafe ], cb);
}

function _testUnsafeCleanupSync(unsafe, cb) {
  _spawnTestWithoutError('unsafe-sync.js', [ 'dir', unsafe ], cb);
}

module.exports.testStat = _testStat;
module.exports.testPrefix = _testPrefix;
module.exports.testPrefixSync = _testPrefixSync;
module.exports.testPostfix = _testPostfix;
module.exports.testPostfixSync = _testPostfixSync;
module.exports.testKeep = _testKeep;
module.exports.testKeepSync = _testKeepSync;
module.exports.testGraceful = _testGraceful;
module.exports.testGracefulSync = _testGracefulSync;
module.exports.assertName = _assertName;
module.exports.assertNameSync = _assertNameSync;
module.exports.testName = _testName;
module.exports.testNameSync = _testNameSync;
module.exports.testUnsafeCleanup = _testUnsafeCleanup;
module.exports.testUnsafeCleanupSync = _testUnsafeCleanupSync;

redpajama_set_name: RedPajamaGithub


text:
#include "thunk_fieldoffset_cond.h"
#include "thunk_type.h"
#include "code_builder.h"

extern CodeBuilder	*code_builder;

using namespace std;

ThunkFieldOffsetCond::~ThunkFieldOffsetCond(void)
{
	delete cond_expr;
	delete true_off;
	if (false_off != NULL) delete false_off;
}

const string ThunkFieldOffsetCond::getPresentFCallName(void) const
{
	return string("__ispresent_") + getOwner()->getType()->getName()
		+ "_" + getFieldName();
}

FCall* ThunkFieldOffsetCond::copyFCallPresent(void) const
{
	return new FCall(
		new Id(getPresentFCallName()),
		getOwner()->copyExprList());
}

ThunkFieldOffsetCond* ThunkFieldOffsetCond::copy(void) const
{
	ThunkFieldOffsetCond	*ret;

	ret = new ThunkFieldOffsetCond(
		cond_expr->copy(),
		true_off->copy(),
		(false_off) ? false_off->copy() : NULL);

	ret->setOwner(getOwner());
	ret->setFieldName(getFieldName());

	return ret;
}

bool ThunkFieldOffsetCond::genProto(void) const
{
	code_builder->genThunkProto(getFCallName());
	code_builder->genThunkProto(getPresentFCallName());
	return true;
}

bool ThunkFieldOffsetCond::genCode(void) const
{
	Expr	*false_expr = NULL;

	if (false_off == NULL)
		false_expr = new Number(0);
	code_builder->genCodeCond(
		getOwner()->getType(),
		getFCallName(),
		cond_expr,
		true_off,
		(false_off) ? false_off : false_expr);
	if (false_expr != NULL) {
		delete false_expr;
		false_expr = NULL;
	}

	/* generate present expr */
	if (false_off != NULL) {
		Expr	*not_present_expr, *present_expr;

		not_present_expr = new Number(0);
		present_expr = new Number(1);

		code_builder->genCodeCond(
			getOwner()->getType(),
			getPresentFCallName(),
			cond_expr,
			present_expr,
			not_present_expr);

		delete not_present_expr;
		delete present_expr;
	} else {
		Expr	*present_expr = new Number(1);
		code_builder->genCode(
			getOwner()->getType(),
			getPresentFCallName(),
			present_expr);
		delete present_expr;
	}

	return true;
}


text:
'use strict';

var check = require('../lib/argCheck');
var io = require('../lib/fileAccess');
var pseudo = require('../lib/pseudoTrans');

exports.start = function (config) {

    if (check.validate(config)){
        var data = io.read(config.fromFile);
        var pseudoed = pseudo.trans(data);
        io.write(config.toFile, pseudoed);

        console.log("Output filename: translation_en_pseudo.json");
        console.log("Done.");
    }

};


text:
<?php

namespace AVHolodnyak\AssetsBusterBundle\DependencyInjection;

use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\Config\FileLocator;

/**
 * Bundle di-extension class.
 *
 * @author Andrey Holodnyak <andrey.holodnyak@gmail.com>
 */
class AssetsBusterExtension extends Extension implements PrependExtensionInterface
{
    /**
     * @inheritdoc
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration($this->getAlias());
        $config = $this->processConfiguration($configuration, $configs);

        $container->setParameter(
            "assets_buster.busters_path",
            $config["busters_path"]
        );
        $container->setParameter(
            "assets_buster.version_format",
            $config["version_format"]
        );

        $loader = new YamlFileLoader(
            $container,
            new FileLocator(__DIR__."/../Resources/config")
        );
        $loader->load("services.yml");
    }

    /**
     * @inheritdoc
     */
    public function getAlias()
    {
        return "assets_buster";
    }

    /**
     * @inheritdoc
     */
    public function prepend(ContainerBuilder $container)
    {
        $container->prependExtensionConfig("framework", array(
            "assets" => array(
                "version_strategy" => "avholodnyak.assets_buster.version_strategy",
            )
        ));
    }
}


text:
from django.db import models

class Settings(models.Model):
    auth_required = models.BooleanField(
        default=True,
        verbose_name="Node Authentication"
    )
    send_images = models.BooleanField(
        default=True,
        verbose_name="Send images to nodes"
    )
    send_posts = models.BooleanField(
        default=True,
        verbose_name="Send posts to nodes"
    )

    class Meta:
        verbose_name_plural = "Settings"

    def __str__(self):
        return "Settings"


text:
			<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
				Toggle navigation

			</button>

						{{men.showName}}

Right


text:
<?php

namespace Nfq\Bundle\SoapBundle\Event;

use Symfony\Component\EventDispatcher\Event;

/**
 * Event being thrown after successful SOAP request/response cycle.
 */
class RequestFinishedEvent extends Event
{
    /**
     * @var string
     */
    private $requestHeaders;

    /**
     * @var string
     */
    private $requestBody;

    /**
     * @var string
     */
    private $responseHeaders;

    /**
     * @var string
     */
    private $responseBody;

    /**
     * @var float In milliseconds.
     */
    private $duration;

    /**
     * @param string $requestHeaders
     * @param string $requestBody
     * @param string $responseHeaders
     * @param string $responseBody
     * @param float  $duration
     */
    public function __construct($requestHeaders, $requestBody, $responseHeaders, $responseBody, $duration)
    {
        $this->requestHeaders = $requestHeaders;
        $this->requestBody = $requestBody;
        $this->responseHeaders = $responseHeaders;
        $this->responseBody = $responseBody;
        $this->duration = $duration;
    }

    /**
     * @return string
     */
    public function getRequestHeaders()
    {
        return $this->requestHeaders;
    }

    /**
     * @return string
     */
    public function getRequestBody()
    {
        return $this->requestBody;
    }

    /**
     * @return string
     */
    public function getResponseHeaders()
    {
        return $this->responseHeaders;
    }

    /**
     * @return string
     */
    public function getResponseBody()
    {
        return $this->responseBody;
    }

    /**
     * @return float
     */
    public function getDuration()
    {
        return $this->duration;
    }
}


text:
.page-header h1 a {
    color: #000;
    text-decoration: none;
}

.CodeMirror {
    height: auto !important;
    border: 1px solid #eee;
}


text:
import logging
from tornado.ioloop import IOLoop
from stormed import Connection, Message

def on_connect():
    ch = conn.channel()
    ch.queue_declare(queue='hello')
    ch.consume('hello', callback, no_ack=True)

def callback(msg):
    print " [x] Received %r" % msg.body

logging.basicConfig()
conn = Connection(host='localhost')
conn.connect(on_connect)
io_loop = IOLoop.instance()
print ' [*] Waiting for messages. To exit press CTRL+C'
try:
    io_loop.start()
except KeyboardInterrupt:
    conn.close(io_loop.stop)


text:
<!doctype html>

  <title>annotations</title>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <link rel="import" href="../../polymer.html">

  <dom-module id="my-component">
    <template>

©

{{myText}}

    </template>
  </dom-module>

Bind correctly?

  <my-component></my-component>


text:
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************

using System;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace Microsoft.Toolkit.Uwp.Services.MicrosoftTranslator
{
    /// <summary>
    /// Client to call Cognitive Services Azure Auth Token service in order to get an access token.
    /// </summary>
    internal class AzureAuthToken
    {
        /// <summary>
        /// Name of header used to pass the subscription key to the token service
        /// </summary>
        private const string OcpApimSubscriptionKeyHeader = "Ocp-Apim-Subscription-Key";

        /// <summary>
        /// URL of the token service
        /// </summary>
        private static readonly Uri ServiceUrl = new Uri("https://api.cognitive.microsoft.com/sts/v1.0/issueToken");

        /// <summary>
        /// After obtaining a valid token, this class will cache it for this duration.
        /// Use a duration of 8 minutes, which is less than the actual token lifetime of 10 minutes.
        /// </summary>
        private static readonly TimeSpan TokenCacheDuration = new TimeSpan(0, 8, 0);

        private static HttpClient client = new HttpClient();

        private string _storedTokenValue = string.Empty;
        private DateTime _storedTokenTime = DateTime.MinValue;
        private string _subscriptionKey;

        /// <summary>
        /// Gets or sets the Service Subscription Key.
        /// </summary>
        public string SubscriptionKey
        {
            get
            {
                return _subscriptionKey;
            }

            set
            {
                if (_subscriptionKey != value)
                {
                    // If the subscription key is changed, the token is no longer valid.
                    _subscriptionKey = value;
                    _storedTokenValue = string.Empty;
                }
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="AzureAuthToken"/> class, that is used to obtain access token
        /// </summary>
        /// <param name="key">Subscription key to use to get an authentication token.</param>
        public AzureAuthToken(string key)
        {
            SubscriptionKey = key;
        }

        /// <summary>
        /// Gets a token for the specified subscription.
        /// </summary>
        /// <returns>The encoded JWT token prefixed with the string "Bearer ".</returns>
        /// <remarks>
        /// This method uses a cache to limit the number of request to the token service.
        /// A fresh token can be re-used during its lifetime of 10 minutes. After a successful
        /// request to the token service, this method caches the access token. Subsequent
        /// invocations of the method return the cached token for the next 8 minutes. After
        /// 8 minutes, a new token is fetched from the token service and the cache is updated.
        /// </remarks>
        public async Task<string> GetAccessTokenAsync()
        {
            if (string.IsNullOrEmpty(_subscriptionKey))
            {
                throw new ArgumentNullException(nameof(SubscriptionKey), "A subscription key is required. Go to Azure Portal and sign up for Microsoft Translator: https://portal.azure.com/#create/Microsoft.CognitiveServices/apitype/TextTranslation");
            }

            // Re-use the cached token if there is one.
            if ((DateTime.Now - _storedTokenTime) < TokenCacheDuration && !string.IsNullOrWhiteSpace(_storedTokenValue))
            {
                return _storedTokenValue;
            }

            using (var request = new HttpRequestMessage(HttpMethod.Post, ServiceUrl))
            {
                request.Headers.Add(OcpApimSubscriptionKeyHeader, SubscriptionKey);

                var response = await client.SendAsync(request).ConfigureAwait(false);
                var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                if (!response.IsSuccessStatusCode)
                {
                    var error = JsonConvert.DeserializeObject<ErrorResponse>(content);
                    throw new TranslatorServiceException(error.Message);
                }

                _storedTokenTime = DateTime.Now;
                _storedTokenValue = $"Bearer {content}";

                return _storedTokenValue;
            }
        }
    }
}


text:
"""App Engine data model (schema) definition for Rietveld."""

import calendar
import datetime
import itertools
import json
import logging
import md5
import os
import re
import sys
import time

from google.appengine.api import memcache
from google.appengine.api import urlfetch
from google.appengine.api.users import User
from google.appengine.ext import db
from google.appengine.ext import ndb

from django.conf import settings

from codereview import auth_utils
from codereview import patching
from codereview import utils
from codereview.exceptions import FetchError

CONTEXT_CHOICES = (3, 10, 25, 50, 75, 100)

### Issues, PatchSets, Patches, Contents, Comments, Messages ###

class Issue(ndb.Model):
  """The major top-level entity.

  It has one or more PatchSets as its descendants.
  """

  subject = ndb.StringProperty(required=True)
  description = ndb.TextProperty()
  project = ndb.StringProperty()
  #: in Subversion - repository path (URL) for files in patch set
  base = ndb.StringProperty()
  repo_guid = ndb.StringProperty()
  owner = auth_utils.AnyAuthUserProperty(auto_current_user_add=True,
                                         required=True)
  created = ndb.DateTimeProperty(auto_now_add=True)
  modified = ndb.DateTimeProperty(auto_now=True)
  reviewers = ndb.StringProperty(repeated=True)
  cc = ndb.StringProperty(repeated=True)
  closed = ndb.BooleanProperty(default=False)
  private = ndb.BooleanProperty(default=False)
  n_comments = ndb.IntegerProperty()

  # NOTE: Use num_messages instead of using n_messages_sent directly.
  n_messages_sent = ndb.IntegerProperty()

  # List of emails that this issue has updates for.
  updates_for = ndb.StringProperty(repeated=True)

  # JSON: {reviewer_email -> [bool|None]}
  reviewer_approval = ndb.TextProperty()

  # JSON: {reviewer_email -> int}
  draft_count_by_user = ndb.TextProperty()

  _is_starred = None
  _has_updates_for_current_user = None
  _original_subject = None

  @property
  def is_starred(self):
    """Whether the current user has this issue starred."""
    if self._is_starred is not None:
      return self._is_starred
    account = Account.current_user_account
    self._is_starred = account is not None and self.key.id() in account.stars
    return self._is_starred

  def user_can_edit(self, user):
    """Returns True if the given user has permission to edit this issue."""
    return user and (user == self.owner or self.is_collaborator(user)
                     or auth_utils.is_current_user_admin())

  @property
  def edit_allowed(self):
    """Whether the current user can edit this issue."""
    return self.user_can_edit(auth_utils.get_current_user())

  def user_can_view(self, user):
    """Returns True if the given user has permission to view this issue."""
    if not self.private:
      return True
    if user is None:
      return False
    email = user.email().lower()
    return (self.user_can_edit(user) or
            email in self.cc or
            email in self.reviewers)

  @property
  def view_allowed(self):
    """Whether the current user can view this issue."""
    return self.user_can_view(auth_utils.get_current_user())

  @property
  def num_messages(self):
    """Get and/or calculate the number of messages sent for this issue."""
    if self.n_messages_sent is None:
      self.calculate_updates_for()
    return self.n_messages_sent

  @num_messages.setter
  def num_messages(self, val):
    """Setter for num_messages."""
    self.n_messages_sent = val

  @property
  def patchsets(self):
    return PatchSet.query(ancestor=self.key).order(Issue.created)

  @property
  def messages(self):
    return Message.query(ancestor=self.key).order(Message.date)

  def update_comment_count(self, n):
    """Increment the n_comments property by n.

    If n_comments in None, compute the count through a query.  (This
    is a transitional strategy while the database contains Issues
    created using a previous version of the schema.)
    """
    if self.n_comments is None:
      self.n_comments = self._get_num_comments()
    self.n_comments += n

  @property
  def num_comments(self):
    """The number of non-draft comments for this issue.

    This is almost an alias for self.n_comments, except that if
    n_comments is None, it is computed through a query, and stored,
    using n_comments as a cache.
    """
    if self.n_comments is None:
      self.n_comments = self._get_num_comments()
    return self.n_comments

  def _get_num_comments(self):
    """Helper to compute the number of comments through a query."""
    return Comment.query(Comment.draft == False, ancestor=self.key).count()

  _num_drafts = None

  def get_num_drafts(self, user):
    """The number of draft comments on this issue for the user.

    The value is expensive to compute, so it is cached.
    """
    if user is None:
      return 0
    assert isinstance(user, User), 'Expected User, got %r instead.' % user
    if self._num_drafts is None:
      if self.draft_count_by_user is None:
        self.calculate_draft_count_by_user()
      else:
        self._num_drafts = json.loads(self.draft_count_by_user)
    return self._num_drafts.get(user.email(), 0)

  def calculate_draft_count_by_user(self):
    """Computes the number of drafts by user and returns the put future.

    Initializes _num_drafts as a side effect.
    """
    self._num_drafts = {}
    query = Comment.query(Comment.draft == True, ancestor=self.key)
    for comment in query:
      cur = self._num_drafts.setdefault(comment.author.email(), 0)
      self._num_drafts[comment.author.email()] = cur + 1
    self.draft_count_by_user = json.dumps(self._num_drafts)

  @staticmethod
  def _collaborator_emails_from_description(description):
    """Parses a description, returning collaborator email addresses.

    Broken out for unit testing.
    """
    collaborators = []
    for line in description.splitlines():
      m = re.match(
        r'\s*COLLABORATOR\s*='
        r'\s*([a-zA-Z0-9._]+@[a-zA-Z0-9_]+\.[a-zA-Z0-9._]+)\s*',
        line)
      if m:
        collaborators.append(m.group(1))
    return collaborators

  def collaborator_emails(self):
    """Returns a possibly empty list of emails specified in
    COLLABORATOR= lines.

    Note that one COLLABORATOR= lines is required per address.
    """
    if not self.description:
      return []
    return Issue._collaborator_emails_from_description(self.description)

  def is_collaborator(self, user):
    """Returns true if the given user is a collaborator on this issue.

    This is determined by checking if the user's email is listed as a
    collaborator email.
    """
    if not user:
      return False
    return user.email() in self.collaborator_emails()

  @property
  def formatted_reviewers(self):
    """Returns a dict from the reviewer to their approval status."""
    if self.reviewer_approval:
      return json.loads(self.reviewer_approval)
    else:
      # Don't have reviewer_approval calculated, so return all reviewers with
      # no approval status.
      return {r: None for r in self.reviewers}

  @property
  def has_updates(self):
    """Returns True if there have been recent updates on this issue for the
    current user.

    If the current user is an owner, this will return True if there are any
    messages after the last message from the owner.
    If the current user is not the owner, this will return True if there has
    been a message from the owner (but not other reviewers) after the
    last message from the current user."""
    if self._has_updates_for_current_user is None:
      user = auth_utils.get_current_user()
      if not user:
        return False
      self._has_updates_for_current_user = (user.email() in self.updates_for)
    return self._has_updates_for_current_user

  def calculate_updates_for(self, *msgs):
    """Recalculates updates_for, reviewer_approval, and draft_count_by_user,
    factoring in msgs which haven't been sent.

    This only updates this Issue object. You'll still need to put() it to
    the data store for it to take effect.
    """
    updates_for_set = set(self.updates_for)
    approval_dict = {r: None for r in self.reviewers}
    self.num_messages = 0
    old_messages = Message.query(Message.draft == False, ancestor=self.key).order(Message.date)
    for msg in itertools.chain(old_messages, msgs):
      if self._original_subject is None:
        self._original_subject = msg.subject
      self.num_messages += 1
      if msg.sender == self.owner.email():
        updates_for_set.update(self.reviewers, self.cc,
                               self.collaborator_emails())
      else:
        updates_for_set.add(self.owner.email())
        if msg.approval:
          approval_dict[msg.sender] = True
        elif msg.disapproval:
          approval_dict[msg.sender] = False
      updates_for_set.discard(msg.sender)
      self.modified = msg.date
    self.updates_for = updates_for_set
    self.reviewer_approval = json.dumps(approval_dict)

  def calculate_and_save_updates_if_None(self):
    """If this Issue doesn't have a valid updates_for or n_messages_sent,
    calculate them and save them back to the datastore.

    Returns a future for the put() operation or None if this issue is up to
    date."""
    if self.n_messages_sent is None:
      if self.draft_count_by_user is None:
        self.calculate_draft_count_by_user()
      self.calculate_updates_for()
      try:
        # Don't change self.modified when filling cache values. AFAICT, there's
        # no better way...
        self.__class__.modified.auto_now = False
        return self.put_async()
      finally:
        self.__class__.modified.auto_now = True

  def mail_subject(self):
    if self._original_subject is None:
      self.calculate_updates_for()
    if self._original_subject is not None:
      return self._original_subject
    return '%s (issue %d by %s)' % (self.subject, self.key.id(), self.owner.email())

  def get_patchset_info(self, user, patchset_id):
    """Returns a list of patchsets for the issue, and calculates/caches data
    into the |patchset_id|'th one with a variety of non-standard attributes.

    Args:
      user (User) - The user to include drafts for.
      patchset_id (int) - The ID of the PatchSet to calculated info for.
        If this is None, it defaults to the newest PatchSet for this Issue.
    """
    patchsets = list(self.patchsets)
    try:
      if not patchset_id and patchsets:
        patchset_id = patchsets[-1].key.id()

      if user:
        drafts = list(Comment.query(
            Comment.draft == True, Comment.author == user, ancestor=self.key))
      else:
        drafts = []
      comments = list(Comment.query(Comment.draft == False, ancestor=self.key))
      # TODO(andi) Remove draft_count attribute, we already have _num_drafts
      # and it's additional magic.
      self.draft_count = len(drafts)
      for c in drafts:
        c.ps_key = c.patch_key.get().patchset_key
      patchset_id_mapping = {}  # Maps from patchset id to its ordering number.
      for patchset in patchsets:
        patchset_id_mapping[patchset.key.id()] = len(patchset_id_mapping) + 1
        patchset.n_drafts = sum(c.ps_key == patchset.key for c in drafts)
        patchset.patches_cache = None
        patchset.parsed_patches = None
        patchset.total_added = 0
        patchset.total_removed = 0
        if patchset_id == patchset.key.id():
          patchset.patches_cache = list(patchset.patches)
          for patch in patchset.patches_cache:
            pkey = patch.key
            patch._num_comments = sum(c.patch_key == pkey for c in comments)
            if user:
              patch._num_my_comments = sum(
                  c.patch_key == pkey and c.author == user
                  for c in comments)
            else:
              patch._num_my_comments = 0
            patch._num_drafts = sum(c.patch_key == pkey for c in drafts)
            # Reduce memory usage: if this patchset has lots of added/removed
            # files (i.e. > 100) then we'll get MemoryError when rendering the
            # response.  Each Patch entity is using a lot of memory if the
            # files are large, since it holds the entire contents.  Call
            # num_chunks and num_drafts first though since they depend on text.
            # These are 'active' properties and have side-effects when looked
            # up.
            # pylint: disable=W0104
            patch.num_chunks
            patch.num_drafts
            patch.num_added
            patch.num_removed
            patch.text = None
            patch._lines = None
            patch.parsed_deltas = []
            for delta in patch.delta:
              # If delta is not in patchset_id_mapping, it's because of internal
              # corruption.
              if delta in patchset_id_mapping:
                patch.parsed_deltas.append([patchset_id_mapping[delta], delta])
              else:
                logging.error(
                    'Issue %d: %d is missing from %s',
                    self.key.id(), delta, patchset_id_mapping)
            if not patch.is_binary:
              patchset.total_added += patch.num_added
              patchset.total_removed += patch.num_removed
      return patchsets
    finally:
      # Reduce memory usage (see above comment).
      for patchset in patchsets:
        patchset.parsed_patches = None

def _calculate_delta(patch, patchset_id, patchsets):
  """Calculates which files in earlier patchsets this file differs from.

  Args:
    patch: The file to compare.
    patchset_id: The file's patchset's key id.
    patchsets: A list of existing patchsets.

  Returns:
    A list of patchset ids.
  """
  delta = []
  if patch.no_base_file:
    return delta
  for other in patchsets:
    if patchset_id == other.key.id():
      break
    if not hasattr(other, 'parsed_patches'):
      other.parsed_patches = None  # cache variable for already parsed patches
    if other.data or other.parsed_patches:
      # Loading all the Patch entities in every PatchSet takes too long
      # (DeadLineExceeded) and consumes a lot of memory (MemoryError) so instead
      # just parse the patchset's data.  Note we can only do this if the
      # patchset was small enough to fit in the data property.
      if other.parsed_patches is None:
        # Late-import engine because engine imports modules.
        from codereview import engine

        # PatchSet.data is stored as ndb.Blob (str). Try to convert it
        # to unicode so that Python doesn't need to do this conversion
        # when comparing text and patch.text, which is ndb.Text
        # (unicode).
        try:
          other.parsed_patches = engine.SplitPatch(other.data.decode('utf-8'))
        except UnicodeDecodeError:  # Fallback to str - unicode comparison.
          other.parsed_patches = engine.SplitPatch(other.data)
        other.data = None  # Reduce memory usage.
      for filename, text in other.parsed_patches:
        if filename == patch.filename:
          if text != patch.text:
            delta.append(other.key.id())
          break
      else:
        # We could not find the file in the previous patchset. It must
        # be new wrt that patchset.
        delta.append(other.key.id())
    else:
      # other (patchset) is too big to hold all the patches inside itself, so
      # we need to go to the datastore.  Use the index to see if there's a
      # patch against our current file in other.
      query = Patch.query(
          Patch.filename == patch.filename, Patch.patchset_key == other.key)
      other_patches = query.fetch(100)
      if other_patches and len(other_patches) > 1:
        logging.info("Got %s patches with the same filename for a patchset",
                     len(other_patches))
      for op in other_patches:
        if op.text != patch.text:
          delta.append(other.key.id())
          break
      else:
        # We could not find the file in the previous patchset. It must
        # be new wrt that patchset.
        delta.append(other.key.id())

  return delta

class PatchSet(ndb.Model):
  """A set of patchset uploaded together.

  This is a descendant of an Issue and has Patches as descendants.
  """
  # name='issue' is needed for backward compatability with existing data.
  # Note: we could write a mapreduce to rewrite data from the issue field
  # to a new issue_key field, which would allow removal of name='issue',
  # but it would require that migration step on every Rietveld instance.
  issue_key = ndb.KeyProperty(name='issue', kind=Issue)  # == parent
  message = ndb.StringProperty()
  data = ndb.BlobProperty()
  url = ndb.StringProperty()
  created = ndb.DateTimeProperty(auto_now_add=True)
  modified = ndb.DateTimeProperty(auto_now=True)
  n_comments = ndb.IntegerProperty(default=0)

  @property
  def patches(self):
    def reading_order(patch):
      """Sort patches by filename, except .h files before .c files."""
      base, ext = os.path.splitext(patch.filename)
      return (base, ext not in ('.h', '.hxx', '.hpp'), ext)

    patch_list = list(Patch.query(ancestor=self.key))
    return sorted(patch_list, key=reading_order)

  def update_comment_count(self, n):
    """Increment the n_comments property by n."""
    self.n_comments = self.num_comments + n

  @property
  def num_comments(self):
    """The number of non-draft comments for this issue.

    This is almost an alias for self.n_comments, except that if
    n_comments is None, 0 is returned.
    """
    # For older patchsets n_comments is None.
    return self.n_comments or 0

  def calculate_deltas(self):
    patchset_id = self.key.id()
    patchsets = None
    q = Patch.query(Patch.delta_calculated == False, ancestor=self.key)
    for patch in q:
      if patchsets is None:
        # patchsets is retrieved on first iteration because patchsets
        # isn't needed outside the loop at all.
        patchsets = list(self.issue_key.get().patchsets)
      patch.delta = _calculate_delta(patch, patchset_id, patchsets)
      patch.delta_calculated = True
      patch.put()

  def nuke(self):
    ps_id = self.key.id()
    patches = []
    for patchset in self.issue_key.get().patchsets:
      if patchset.created <= self.created:
        continue
      patches.extend(
        p for p in patchset.patches if p.delta_calculated and ps_id in p.delta)

    def _patchset_delete(patches):
      """Transactional helper for delete_patchset.

      Args:
        patches: Patches that have delta against patches of ps_delete.

      """
      patchset_id = self.key.id()
      tbp = []
      for patch in patches:
        patch.delta.remove(patchset_id)
        tbp.append(patch)
      if tbp:
        ndb.put_multi(tbp)
      tbd = [self]
      for cls in [Patch, Comment]:
        tbd.extend(cls.query(ancestor=self.key))
      ndb.delete_multi(entity.key for entity in tbd)
    ndb.transaction(lambda: _patchset_delete(patches))

class Message(ndb.Model):
  """A copy of a message sent out in email.

  This is a descendant of an Issue.
  """
  # name='issue' is needed for backward compatability with existing data.
  issue_key = ndb.KeyProperty(name='issue', kind=Issue)  # == parent
  subject = ndb.StringProperty()
  sender = ndb.StringProperty()
  recipients = ndb.StringProperty(repeated=True)
  date = ndb.DateTimeProperty(auto_now_add=True)
  text = ndb.TextProperty()
  draft = ndb.BooleanProperty(default=False)
  in_reply_to_key = ndb.KeyProperty(name='in_reply_to', kind='Message')
  issue_was_closed = ndb.BooleanProperty(default=False)

  _approval = None
  _disapproval = None

  LGTM_RE = re.compile(r'\blgtm\b')
  NOT_LGTM_RE = re.compile(r'\bnot lgtm\b')

  def find(self, regex, owner_allowed=False):
    """Returns True when the message has a string matching regex in it.

    - Must not be written by the issue owner.
    - Must contain regex in a line that doesn't start with '>'.
    """
    issue = self.issue_key.get()
    if not owner_allowed and issue.owner.email() == self.sender:
      return False
    return any(
        True for line in self.text.lower().splitlines()
        if not line.strip().startswith('>') and regex.search(line))

  @property
  def approval(self):
    """Is True when the message represents an approval of the review."""
    if self._approval is None:
      self._approval = self.find(self.LGTM_RE) and not self.disapproval
    return self._approval

  @property
  def disapproval(self):
    """Is True when the message represents a disapproval of the review."""
    if self._disapproval is None:
      self._disapproval = self.find(self.NOT_LGTM_RE)
    return self._disapproval

class Content(ndb.Model):
  """The content of a text file.

  This is a descendant of a Patch.
  """

  # parent => Patch
  text = ndb.TextProperty()
  data = ndb.BlobProperty()
  # Checksum over text or data depending on the type of this content.
  checksum = ndb.TextProperty()
  is_uploaded = ndb.BooleanProperty(default=False)
  is_bad = ndb.BooleanProperty(default=False)
  file_too_large = ndb.BooleanProperty(default=False)

  @property
  def lines(self):
    """The text split into lines, retaining line endings."""
    if not self.text:
      return []
    return self.text.splitlines(True)

class Patch(ndb.Model):
  """A single patch, i.e. a set of changes to a single file.

  This is a descendant of a PatchSet.
  """

  patchset_key = ndb.KeyProperty(name='patchset', kind=PatchSet)  # == parent
  filename = ndb.StringProperty()
  status = ndb.StringProperty()  # 'A', 'A  +', 'M', 'D' etc
  text = ndb.TextProperty()
  content_key = ndb.KeyProperty(name='content', kind=Content)
  patched_content_key = ndb.KeyProperty(name='patched_content', kind=Content)
  is_binary = ndb.BooleanProperty(default=False)
  # Ids of patchsets that have a different version of this file.
  delta = ndb.IntegerProperty(repeated=True)
  delta_calculated = ndb.BooleanProperty(default=False)

  _lines = None

  @property
  def lines(self):
    """The patch split into lines, retaining line endings.

    The value is cached.
    """
    if self._lines is not None:
      return self._lines

    # Note that self.text has already had newlines normalized on upload.
    # And, any ^L characters are explicitly not treated as breaks.
    bare_lines = self.text.split('\n')
    self._lines = [bare_line + '\n' for bare_line in bare_lines]
    return self._lines

  _property_changes = None

  @property
  def property_changes(self):
    """The property changes split into lines.

    The value is cached.
    """
    if self._property_changes != None:
      return self._property_changes
    self._property_changes = []
    match = re.search('^Property changes on.*\n'+'_'*67+'$', self.text,
                      re.MULTILINE)
    if match:
      self._property_changes = self.text[match.end():].splitlines()
    return self._property_changes

  _num_added = None

  @property
  def num_added(self):
    """The number of line additions in this patch.

    The value is cached.
    """
    if self._num_added is None:
      self._num_added = self.count_startswith('+') - 1
    return self._num_added

  _num_removed = None

  @property
  def num_removed(self):
    """The number of line removals in this patch.

    The value is cached.
    """
    if self._num_removed is None:
      self._num_removed = self.count_startswith('-') - 1
    return self._num_removed

  _num_chunks = None

  @property
  def num_chunks(self):
    """The number of 'chunks' in this patch.

    A chunk is a block of lines starting with '@@'.

    The value is cached.
    """
    if self._num_chunks is None:
      self._num_chunks = self.count_startswith('@@')
    return self._num_chunks

  _num_comments = None

  @property
  def num_comments(self):
    """The number of non-draft comments for this patch.

    The value is cached.
    """
    if self._num_comments is None:
      self._num_comments = Comment.query(
          Comment.patch_key == self.key, Comment.draft == False).count()
    return self._num_comments

  _num_my_comments = None

  def num_my_comments(self):
    """The number of non-draft comments for this patch by the logged in user.

    The value is cached.
    """
    if self._num_my_comments is None:
      account = Account.current_user_account
      if account is None:
        self._num_my_comments = 0
      else:
        query = Comment.query(
            Comment.patch_key == self.key, Comment.draft == False,
            Comment.author == account.user)
        self._num_my_comments = query.count()
    return self._num_my_comments

  _num_drafts = None

  @property
  def num_drafts(self):
    """The number of draft comments on this patch for the current user.

    The value is expensive to compute, so it is cached.
    """
    if self._num_drafts is None:
      account = Account.current_user_account
      if account is None:
        self._num_drafts = 0
      else:
        query = Comment.query(
            Comment.patch_key == self.key, Comment.draft == True,
            Comment.author == account.user)
        self._num_drafts = query.count()
    return self._num_drafts

  def count_startswith(self, prefix):
    """Returns the number of lines with the specified prefix."""
    return len([l for l in self.lines if l.startswith(prefix)])

  def get_content(self):
    """Get self.content, or fetch it if necessary.

    This is the content of the file to which this patch is relative.

    Returns:
      a Content instance.

    Raises:
      FetchError: If there was a problem fetching it.
    """
    try:
      if self.content_key is not None:
        content = self.content_key.get()
        if content.is_bad:
          msg = 'Bad content. Try to upload again.'
          logging.warn('Patch.get_content: %s', msg)
          raise FetchError(msg)
        if content.is_uploaded and content.text == None:
          msg = 'Upload in progress.'
          logging.warn('Patch.get_content: %s', msg)
          raise FetchError(msg)
        else:
          return content
    except db.Error:
      # This may happen when a Content entity was deleted behind our back.
      self.content_key = None

    content = self.fetch_base()
    content.put()
    self.content_key = content.key
    self.put()
    return content

  def get_patched_content(self):
    """Get this patch's patched_content, computing it if necessary.

    This is the content of the file after applying this patch.

    Returns:
      a Content instance.

    Raises:
      FetchError: If there was a problem fetching the old content.
    """
    try:
      if self.patched_content_key is not None:
        return self.patched_content_key.get()
    except db.Error:
      # This may happen when a Content entity was deleted behind our back.
      self.patched_content_key = None

    old_lines = self.get_content().text.splitlines(True)
    logging.info('Creating patched_content for %s', self.filename)
    chunks = patching.ParsePatchToChunks(self.lines, self.filename)
    new_lines = []
    for _, _, new in patching.PatchChunks(old_lines, chunks):
      new_lines.extend(new)
    text = ''.join(new_lines)
    patched_content = Content(text=text, parent=self.key)
    patched_content.put()
    self.patched_content_key = patched_content.key
    self.put()
    return patched_content

  @property
  def no_base_file(self):
    """Returns True iff the base file is not available."""
    return self.content_key and self.content_key.get().file_too_large

  def fetch_base(self):
    """Fetch base file for the patch.

    Returns:
      A models.Content instance.

    Raises:
      FetchError: For any kind of problem fetching the content.
    """
    rev = patching.ParseRevision(self.lines)
    if rev is not None:
      if rev == 0:
        # rev=0 means it's a new file.
        return Content(text=u'', parent=self.key)

    # AppEngine can only fetch URLs that db.Link() thinks are OK,
    # so try converting to a db.Link() here.
    issue = self.patchset_key.get().issue_key.get()
    try:
      base = db.Link(issue.base)
    except db.BadValueError:
      msg = 'Invalid base URL for fetching: %s' % issue.base
      logging.warn(msg)
      raise FetchError(msg)

    url = utils.make_url(base, self.filename, rev)
    logging.info('Fetching %s', url)
    try:
      result = urlfetch.fetch(url, validate_certificate=True)
    except urlfetch.Error, err:
      msg = 'Error fetching %s: %s: %s' % (url, err.__class__.__name__, err)
      logging.warn('FetchBase: %s', msg)
      raise FetchError(msg)
    if result.status_code != 200:
      msg = 'Error fetching %s: HTTP status %s' % (url, result.status_code)
      logging.warn('FetchBase: %s', msg)
      raise FetchError(msg)
    return Content(text=utils.to_dbtext(utils.unify_linebreaks(result.content)),
                   parent=self.key)

class Comment(ndb.Model):
  """A Comment for a specific line of a specific file.

  This is a descendant of a Patch.
  """

  patch_key = ndb.KeyProperty(name='patch', kind=Patch)  # == parent
  message_id = ndb.StringProperty()  # == key_name
  author = auth_utils.AnyAuthUserProperty(auto_current_user_add=True)
  date = ndb.DateTimeProperty(auto_now=True)
  lineno = ndb.IntegerProperty()
  text = ndb.TextProperty()
  left = ndb.BooleanProperty()
  draft = ndb.BooleanProperty(required=True, default=True)

  buckets = None
  shorttext = None

  def complete(self):
    """Set the shorttext and buckets attributes."""
    # TODO(guido): Turn these into caching proprties instead.

    # The strategy for buckets is that we want groups of lines that
    # start with > to be quoted (and not displayed by
    # default). Whitespace-only lines are not considered either quoted
    # or not quoted. Same goes for lines that go like "On ... user
    # wrote:".
    cur_bucket = []
    quoted = None
    self.buckets = []

    def _Append():
      if cur_bucket:
        self.buckets.append(Bucket(text="\n".join(cur_bucket),
                                   quoted=bool(quoted)))

    lines = self.text.splitlines()
    for line in lines:
      if line.startswith("On ") and line.endswith(":"):
        pass
      elif line.startswith(">"):
        if quoted is False:
          _Append()
          cur_bucket = []
        quoted = True
      elif line.strip():
        if quoted is True:
          _Append()
          cur_bucket = []
        quoted = False
      cur_bucket.append(line)

    _Append()

    self.shorttext = self.text.lstrip()[:50].rstrip()
    # Grab the first 50 chars from the first non-quoted bucket
    for bucket in self.buckets:
      if not bucket.quoted:
        self.shorttext = bucket.text.lstrip()[:50].rstrip()
        break

class Bucket(ndb.Model):
  """A 'Bucket' of text.

  A comment may consist of multiple text buckets, some of which may be
  collapsed by default (when they represent quoted text).

  NOTE: This entity is never written to the database.  See Comment.complete().
  """
  # TODO(guido): Flesh this out.

  text = ndb.TextProperty()
  quoted = ndb.BooleanProperty()

### Repositories and Branches ###

class Repository(ndb.Model):
  """A specific Subversion repository."""

  name = ndb.StringProperty(required=True)
  url = ndb.StringProperty(required=True)
  owner = auth_utils.AnyAuthUserProperty(auto_current_user_add=True)
  guid = ndb.StringProperty()  # global unique repository id

  def __str__(self):
    return self.name

BRANCH_CATEGORY_CHOICES = ('*trunk*', 'branch', 'tag')

class Branch(ndb.Model):
  """A trunk, branch, or a tag in a specific Subversion repository."""

  repo_key = ndb.KeyProperty(name='repo', kind=Repository, required=True)
  # Cache repo.name as repo_name, to speed up set_branch_choices()
  # in views.IssueBaseForm.
  repo_name = ndb.StringProperty()
  category = ndb.StringProperty(required=True, choices=BRANCH_CATEGORY_CHOICES)
  name = ndb.StringProperty(required=True)
  url = ndb.StringProperty(required=True)
  owner = auth_utils.AnyAuthUserProperty(auto_current_user_add=True)

### Accounts ###

class Account(ndb.Model):
  """Maps a user or email address to a user-selected nickname, and more.

  Nicknames do not have to be unique.

  The default nickname is generated from the email address by
  stripping the first '@' sign and everything after it.  The email
  should not be empty nor should it start with '@' (AssertionError
  error is raised if either of these happens).

  This also holds a list of ids of starred issues.  The expectation
  that you won't have more than a dozen or so starred issues (a few
  hundred in extreme cases) and the memory used up by a list of
  integers of that size is very modest, so this is an efficient
  solution.  (If someone found a use case for having thousands of
  starred issues we'd have to think of a different approach.)
  """

  user = auth_utils.AnyAuthUserProperty(auto_current_user_add=True,
                                        required=True)
  email = ndb.StringProperty(required=True)  # key == <email>
  nickname = ndb.StringProperty(required=True)
  default_context = ndb.IntegerProperty(default=settings.DEFAULT_CONTEXT,
                                        choices=CONTEXT_CHOICES)
  default_column_width = ndb.IntegerProperty(
      default=settings.DEFAULT_COLUMN_WIDTH)
  created = ndb.DateTimeProperty(auto_now_add=True)
  modified = ndb.DateTimeProperty(auto_now=True)
  stars = ndb.IntegerProperty(repeated=True)  # Issue ids of all starred issues
  fresh = ndb.BooleanProperty()
  notify_by_email = ndb.BooleanProperty(default=True)
  # Spammer; only blocks sending messages, not uploading issues.
  blocked = ndb.BooleanProperty(default=False)

  # Current user's Account.  Updated by middleware.AddUserToRequestMiddleware.
  current_user_account = None

  lower_email = ndb.ComputedProperty(lambda self: self.email.lower())
  lower_nickname = ndb.ComputedProperty(lambda self: self.nickname.lower())
  xsrf_secret = ndb.BlobProperty()

  @classmethod
  def get_id_for_email(cls, email):
    return '<%s>' % email

  @classmethod
  def get_account_for_user(cls, user):
    """Get the Account for a user, creating a default one if needed."""
    email = user.email()
    assert email
    id_str = cls.get_id_for_email(email)
    # Since usually the account already exists, first try getting it
    # without the transaction implied by get_or_insert().
    account = cls.get_by_id(id_str)
    if account is not None:
      return account
    nickname = cls.create_nickname_for_user(user)
    return cls.get_or_insert(
      id_str, user=user, email=email, nickname=nickname, fresh=True)

  @classmethod
  def create_nickname_for_user(cls, user):
    """Returns a unique nickname for a user."""
    name = nickname = user.email().split('@', 1)[0]
    next_char = chr(ord(nickname[0].lower())+1)
    existing_nicks = [
      account.lower_nickname for account in cls.query(
          cls.lower_nickname >= nickname.lower(),
          cls.lower_nickname < next_char)]
    suffix = 0
    while nickname.lower() in existing_nicks:
      suffix += 1
      nickname = '%s%d' % (name, suffix)
    return nickname

  @classmethod
  def get_nickname_for_user(cls, user):
    """Get the nickname for a user."""
    return cls.get_account_for_user(user).nickname

  @classmethod
  def get_account_for_email(cls, email):
    """Get the Account for an email address, or return None."""
    assert email
    id_str = '<%s>' % email
    return cls.get_by_id(id_str)

  @classmethod
  def get_accounts_for_emails(cls, emails):
    """Get the Accounts for each of a list of email addresses."""
    keys = [ndb.Key(cls, '<%s>' % email) for email in emails]
    return ndb.get_multi(keys)

  @classmethod
  def get_multiple_accounts_by_email(cls, emails):
    """Get multiple accounts.  Returns a dict by email."""
    results = {}
    keys = []
    for email in emails:
      if cls.current_user_account and email == cls.current_user_account.email:
        results[email] = cls.current_user_account
      else:
        keys.append(ndb.Key(cls,'<%s>' % email))
    if keys:
      accounts = ndb.get_multi(keys)
      for account in accounts:
        if account is not None:
          results[account.email] = account
    return results

  @classmethod
  def get_nickname_for_email(cls, email, default=None):
    """Get the nickname for an email address, possibly a default.

    If default is None a generic nickname is computed from the email
    address.

    Args:
      email: email address.
      default: If given and no account is found, returned as the default value.
    Returns:
      Nickname for given email.
    """
    account = cls.get_account_for_email(email)
    if account is not None and account.nickname:
      return account.nickname
    if default is not None:
      return default
    return email.replace('@', '_')

  @classmethod
  def get_account_for_nickname(cls, nickname):
    """Get the list of Accounts that have this nickname."""
    assert nickname
    assert '@' not in nickname
    return cls.query(cls.lower_nickname == nickname.lower()).get()

  @classmethod
  def get_email_for_nickname(cls, nickname):
    """Turn a nickname into an email address.

    If the nickname is not unique or does not exist, this returns None.
    """
    account = cls.get_account_for_nickname(nickname)
    if account is None:
      return None
    return account.email

  def user_has_selected_nickname(self):
    """Return True if the user picked the nickname.

    Normally this returns 'not self.fresh', but if that property is
    None, we assume that if the created and modified timestamp are
    within 2 seconds, the account is fresh (i.e. the user hasn't
    selected a nickname yet).  We then also update self.fresh, so it
    is used as a cache and may even be written back if we're lucky.
    """
    if self.fresh is None:
      delta = self.created - self.modified
      # Simulate delta = abs(delta)
      if delta.days < 0:
        delta = -delta
      self.fresh = (delta.days == 0 and delta.seconds < 2)
    return not self.fresh

  _drafts = None

  @property
  def drafts(self):
    """A list of issue ids that have drafts by this user.

    This is cached in memcache.
    """
    if self._drafts is None:
      if self._initialize_drafts():
        self._save_drafts()
    return self._drafts

  def update_drafts(self, issue, have_drafts=None):
    """Update the user's draft status for this issue.

    Args:
      issue: an Issue instance.
      have_drafts: optional bool forcing the draft status.  By default,
          issue.num_drafts is inspected (which may query the datastore).

    The Account is written to the datastore if necessary.
    """
    dirty = False
    if self._drafts is None:
      dirty = self._initialize_drafts()
    keyid = issue.key.id()
    if have_drafts is None:
      # Beware, this may do a query.
      have_drafts = bool(issue.get_num_drafts(self.user))
    if have_drafts:
      if keyid not in self._drafts:
        self._drafts.append(keyid)
        dirty = True
    else:
      if keyid in self._drafts:
        self._drafts.remove(keyid)
        dirty = True
    if dirty:
      self._save_drafts()

  def _initialize_drafts(self):
    """Initialize self._drafts from scratch.

    This mostly exists as a schema conversion utility.

    Returns:
      True if the user should call self._save_drafts(), False if not.
    """
    drafts = memcache.get('user_drafts:' + self.email)
    if drafts is not None:
      self._drafts = drafts
      ##logging.info('HIT: %s -> %s', self.email, self._drafts)
      return False
    # We're looking for the Issue key id.  The ancestry of comments goes:
    # Issue -> PatchSet -> Patch -> Comment.
    draft_query = Comment.query(
        Comment.author == self.user, Comment.draft == True)
    issue_ids = set(comment.key.parent().parent().parent().id()
                    for comment in draft_query)
    self._drafts = list(issue_ids)
    ##logging.info('INITIALIZED: %s -> %s', self.email, self._drafts)
    return True

  def _save_drafts(self):
    """Save self._drafts to memcache."""
    ##logging.info('SAVING: %s -> %s', self.email, self._drafts)
    memcache.set('user_drafts:' + self.email, self._drafts, 3600)

  def get_xsrf_token(self, offset=0):
    """Return an XSRF token for the current user."""
    # This code assumes that
    # self.user.email() == auth_utils.get_current_user().email()
    current_user = auth_utils.get_current_user()
    if self.user.user_id() != current_user.user_id():
      # Mainly for Google Account plus conversion.
      logging.info('Updating user_id for %s from %s to %s' % (
        self.user.email(), self.user.user_id(), current_user.user_id()))
      self.user = current_user
      self.put()
    if not self.xsrf_secret:
      self.xsrf_secret = os.urandom(8)
      self.put()
    m = md5.new(self.xsrf_secret)
    email_str = self.lower_email
    if isinstance(email_str, unicode):
      email_str = email_str.encode('utf-8')
    m.update(self.lower_email)
    when = int(time.time()) // 3600 + offset
    m.update(str(when))
    return m.hexdigest()

### Statistics ###

def compute_score(stats):
  """Calculates the score used for the leaderboard.

  If this function is changed, every AccountStats* must be stored again to
  update the score. Lower, the better.

  If this function is updated, also update the legend in
  templates/leaderboard.html.
  """
  score = stats.median_latency
  if score is None:
    return AccountStatsBase.NULL_SCORE
  # - Penalize people who do not respond to their reviews.
  # - People without any lgtm have a bonus +100 score downgrade.
  value = float(score) / stats.nb_reviewed / stats.percent_reviewed
  if not stats.nb_lgtmed:
    value += 100
  return value

class AccountStatsBase(ndb.Model):
  """Base class for Statistics for a single user covering a specific time span.

  Parent is always the corresponding Account.

  There's 3 types of entity types:
  1. Single day summary. AccountStatsDay. Key name is 'YYYY-MM-DD'.
  2. Single month summary. AccountStatsMulti. Key name is 'YYYY-MM'.
  3. 'XX last days' rolling summary. AccountStatsMulti. Key name is the string
     'XX'.

  The statistics encompass all the reviews WHERE THE INITIAL EMAIL WAS SENT IN
  THE DAY. This is important, it's not 'when the issue was created' neither when
  the reviewer woke up. This means finally reviewing a week old CL will worsen
  your score of last week. This could create a bad incentive, but if you punted
  on a review for a week, the author already hates you anyway.

  WARNING: entities can be updated several days after the day they represent, as
  stated in the previous paragraph.

  CLs where no message was ever sent are not considered, since the date is
  pinned on the first message.

  Users that never created an Issue are not considered. See
  views.figure_out_real_accounts().

  In each case, the entity won't exist if the user had no activity, so the
  number of entities scales linearly with the activty going on. More
  specifically for the rolling summary, the entity will only exist if the user
  had activity in the past XX days, as it will be deleted otherwise on the next
  cron job run.

  This entity is written by a cron job once per day per account that had
  activity, so it doesn't need to be updated in a transaction, reducing the
  strain on the datastore. By precomputing the rolling summary, it makes
  displaying the leaderboard seamless performance-wise.
  """
  # These values are types of review where no latency can be calculated:
  # - NORMAL (1): A normal code review.
  # - IGNORED (2): The reviewer hasn't reviewed yet.
  # - DRIVE_BY (3): The reviewer sent a comment while not being on the reviewer
  #                 list before commenting.
  # - NOT_REQUESTED (4): A reviewer commented on an Issue before the author
  #                      published a request for review, so no latency can be
  #                      calculated.
  # - OUTGOING (5): Set for the issue author so he can track how many CLs he
  #                 sent.
  NORMAL, IGNORED, DRIVE_BY, NOT_REQUESTED, OUTGOING = range(1, 6)
  REVIEW_TYPES = [
    None,
    'normal',
    'ignored',
    'drive-by',
    'not requested',
    'outgoing',
  ]

  # Store this value instead of None when the score would be None. Must be a
  # float.
  NULL_SCORE = sys.float_info.max

  # Saved so incomplete cronjob/taskqueue execution can be safely recovered.
  modified = ndb.DateTimeProperty(auto_now=True)

  # Issues. The actual issues considered. Must be non-empty.
  issues = ndb.IntegerProperty(repeated=True)
  # Latencies. List of "request to review" latencies in seconds. Must be in the
  # same order than issues. Issues not reviewed are to be set to < 0.
  latencies = ndb.IntegerProperty(repeated=True)
  # Number of LGTMs for each issue in .issues.
  lgtms = ndb.IntegerProperty(repeated=True)
  # Type of review. Must be one of NORMAL, IGNORED, NOT_REQUESTED, OUTGOING.
  review_types = ndb.IntegerProperty(repeated=True)

  # Computed properties.

  # The same value as .key.id(). Used to do a quick search for every
  # instances for a specific day, month or rolling summary for the leaderboard.
  name = ndb.ComputedProperty(lambda x: x.key.id())
  # Used for the leaderboard. Do not use ComputeProperty() so
  # task_refresh_all_stats_score can determine if the entity needs to be saved
  # again or not.
  score = ndb.FloatProperty(default=NULL_SCORE)

  @property
  def nb_reviewed(self):
    """Total reviews requests where the user replied where a latency can be
    calculated.
    """
    return sum(
        self.review_types[i] != self.OUTGOING and self.latencies[i] >= 0
        for i in xrange(len(self.issues)))

  @property
  def nb_ignored(self):
    """Number of issues the user didn't review yet but should."""
    return sum(r == self.IGNORED for r in self.review_types)

  @property
  def nb_issues(self):
    """Number of issues either reviewed or ignored excluding outgoing issues."""
    return sum(r != self.OUTGOING for r in self.review_types)

  @property
  def nb_lgtmed(self):
    """Number of issues LGTMed."""
    return sum(
        self.review_types[i] != self.OUTGOING and self.lgtms[i] > 0
        for i in xrange(len(self.issues)))

  @property
  def nb_drive_by(self):
    """Number of issues that got a drive by by this user, e.g. the user never
    got a formal issue review request.
    """
    return sum(r == self.DRIVE_BY for r in self.review_types)

  @property
  def nb_not_requested(self):
    """Number of issues where the reviewer sent his comments without the author
    even asking for a review. This can happen if the author asked for a review
    out of band, like by IM.
    """
    return sum(r == self.NOT_REQUESTED for r in self.review_types)

  @property
  def nb_outgoing(self):
    """Number of issues the user sent."""
    return sum(r == self.OUTGOING for r in self.review_types)

  @property
  def self_love(self):
    """How much the user likes to auto-congratulate himself on his own reviews.
    """
    # self.self_love + self.nb_lgtmed == sum(l > 0 for l in self.lgtms[i])
    return sum(
        self.review_types[i] == self.OUTGOING and self.lgtms[i] > 0
        for i in xrange(len(self.issues)))

  @property
  def latencies_sorted(self):
    return sorted(self.latencies)

  @property
  def median_latency(self):
    """Calculates the median latency to store in the datastore."""
    latencies = sorted(l for l in self.latencies if l >= 0)
    if not latencies:
      return None
    length = len(latencies)
    if (length & 1) == 0:
      return (latencies[length/2] + latencies[length/2-1]) / 2.
    else:
      return latencies[length/2]

  @property
  def average_latency(self):
    """The average review latency.

    The average is much less useful than the median, since the distribution is
    more Poisson-like than a bell curve.
    """
    latencies = [l for l in self.latencies if l >= 0]
    if not latencies:
      return None
    return sum(latencies) / float(len(latencies))

  @property
  def percent_reviewed(self):
    """Percentage of issues reviewed out of total incoming issues."""
    if not self.nb_issues:
      return 0
    return self.nb_reviewed * 100. / self.nb_issues

  @property
  def percent_lgtm(self):
    """Percentage of issues LGTMed out of total incoming issues."""
    if not self.nb_issues:
      return 0
    return self.nb_lgtmed * 100. / self.nb_issues

  @property
  def user(self):
    """Returns the corresponding Account key: the user's email address."""
    return self.key.parent().id()[1:-1]

  @property
  def user_short(self):
    """Strips the last part of domain off |.user| to save space."""
    return self.key.parent().id()[1:-1].rsplit('.', 1)[0]

  def _pre_put_hook(self):
    """Updates the score before saving."""
    # Save headaches and asserts internal consistency. This code can be
    # commented out once its is known to work.
    assert (
        len(self.issues) == len(self.lgtms) == len(self.latencies) ==
        len(self.review_types)), str(self)
    assert all(i >= 0 for i in self.lgtms), str(self)
    assert all(i >= -1 for i in self.latencies), str(self)
    assert all(self.NORMAL <= i <= self.OUTGOING for i in self.review_types), (
        str(self))
    for i in xrange(len(self.issues)):
      r = self.review_types[i]
      lg = self.lgtms[i]
      la = self.latencies[i]
      assert not (lg and r == self.IGNORED), str(self)
      if la >= 0:
        assert r in (self.NORMAL, self.DRIVE_BY, self.NOT_REQUESTED), str(self)
      else:
        assert r in (self.IGNORED, self.OUTGOING), str(self)

    # Always recalculate the score.
    self.score = compute_score(self)

  def to_dict(self):
    out = super(AccountStatsBase, self).to_dict()
    del out['modified']
    return out

class AccountStatsDay(AccountStatsBase):
  """Statistics for a single day.

  Using a separate entity type for summaries saves an index.
  """
  days = 1

class AccountStatsMulti(AccountStatsBase):
  # Cache the number of days covered by this entity.
  _days = None

  @property
  def days(self):
    """Number of days covered by this entity.

    Guaranteed to be >=1.
    """
    if not self._days:
      if self.name.isdigit():
        # It is a rolling summary.
        self._days = int(self.name)
      else:
        quarter = quarter_to_months(self.name)
        if not quarter:
          # It's a month.
          year, month = self.name.split('-', 1)
          self._days = calendar.monthrange(int(year), int(month))[1]
        else:
          self._days = sum(
              calendar.monthrange(map(int, i.split('-')))[1] for i in quarter)
    return self._days

  @property
  def per_day_reviews_received(self):
    """Average number of issues incoming per day."""
    return float(self.nb_issues) / self.days

  @property
  def per_day_reviews_done(self):
    """Average number of reviews done per day.

    Including drive bys, unrequested and self reviews.
    """
    return float(self.nb_reviewed) / self.days

def quarter_to_months(when):
  """Manually handles the form 'YYYY-QX'."""
  quarter = re.match(r'^(\d\d\d\d-)[qQ]([1-4])$', when)
  if not quarter:
    return None
  prefix = quarter.group(1)
  # Convert the quarter into 3 months group.
  base = (int(quarter.group(2)) - 1) * 4 + 1
  return ['%s%02d' % (prefix, i) for i in range(base, base+3)]

def verify_account_statistics_name(name):
  """Returns True if the key name is valid for an entity."""
  if name.isdigit():
    # Only allows 30 rolling days for now.
    return name == '30'

  if not re.match(r'^\d\d\d\d-\d\d(|-\d\d)$', name):
    return False
  # At that point, it's guaranteed to be somewhat date formed. Validate it's a
  # valid calendar day or month.
  parts = map(int, name.split('-'))
  # Accept only years [2008-current].
  if parts[0] > datetime.date.today().year or parts[0] < 2008:
    return False

  try:
    # Verify the calendar date.
    if len(parts) == 3:
      datetime.date(*parts)
    else:
      datetime.date(*parts, day=1)
    return True
  except ValueError:
    return False

def sum_account_statistics(out, items):
  """Updates |out| entity with the sum of all |items|.

  Returns True if the entity changed, False if the same values were calculated.
  In that case, it's not necessary to save the entity back in the datastore,
  it's unchanged.
  """
  prev_issues = out.issues
  prev_latencies = out.latencies
  prev_lgtms = out.lgtms
  prev_review_types = out.review_types

  out.issues = sum((i.issues for i in items), [])
  out.latencies = sum((i.latencies for i in items), [])
  out.lgtms = sum((i.lgtms for i in items), [])
  out.review_types = sum((i.review_types for i in items), [])
  out.score = compute_score(out)
  return (
      prev_issues != out.issues or
      prev_latencies != out.latencies or
      prev_lgtms != out.lgtms or
      prev_review_types != out.review_types)


text:
package com.frank;

/**
 * Created by frank on 2016/1/30.
 */
public class ConcreteStrategyA implements Strategy {
    @Override
    public void algrithmInterface() {
        System.out.println("test ConcreteStrategyA.....");
    }
}


text:
package beta

import (
	"context"
	"fmt"
	"time"

	"google.golang.org/api/googleapi"
	"github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl"
)

type NetworkFirewallPolicyAssociation struct {
	Name             *string `json:"name"`
	AttachmentTarget *string `json:"attachmentTarget"`
	FirewallPolicy   *string `json:"firewallPolicy"`
	ShortName        *string `json:"shortName"`
	Location         *string `json:"location"`
	Project          *string `json:"project"`
}

func (r *NetworkFirewallPolicyAssociation) String() string {
	return dcl.SprintResource(r)
}

// Describe returns a simple description of this resource to ensure that automated tools
// can identify it.
func (r *NetworkFirewallPolicyAssociation) Describe() dcl.ServiceTypeVersion {
	return dcl.ServiceTypeVersion{
		Service: "compute",
		Type:    "NetworkFirewallPolicyAssociation",
		Version: "beta",
	}
}

func (r *NetworkFirewallPolicyAssociation) ID() (string, error) {
	if err := extractNetworkFirewallPolicyAssociationFields(r); err != nil {
		return "", err
	}
	nr := r.urlNormalized()
	params := map[string]interface{}{
		"name":              dcl.ValueOrEmptyString(nr.Name),
		"attachment_target": dcl.ValueOrEmptyString(nr.AttachmentTarget),
		"firewall_policy":   dcl.ValueOrEmptyString(nr.FirewallPolicy),
		"short_name":        dcl.ValueOrEmptyString(nr.ShortName),
		"location":          dcl.ValueOrEmptyString(nr.Location),
		"project":           dcl.ValueOrEmptyString(nr.Project),
	}
	if dcl.IsRegion(nr.Location) {
		return dcl.Nprintf("projects/{{project}}/regions/{{location}}/firewallPolicies/{{firewall_policy}}/getAssociation?name={{name}}", params), nil
	}

	return dcl.Nprintf("projects/{{project}}/global/firewallPolicies/{{firewall_policy}}/getAssociation?name={{name}}", params), nil
}

const NetworkFirewallPolicyAssociationMaxPage = -1

type NetworkFirewallPolicyAssociationList struct {
	Items []*NetworkFirewallPolicyAssociation

	nextToken string

	pageSize int32

	resource *NetworkFirewallPolicyAssociation
}

func (l *NetworkFirewallPolicyAssociationList) HasNext() bool {
	return l.nextToken != ""
}

func (l *NetworkFirewallPolicyAssociationList) Next(ctx context.Context, c *Client) error {
	ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second))
	defer cancel()

	if !l.HasNext() {
		return fmt.Errorf("no next page")
	}
	items, token, err := c.listNetworkFirewallPolicyAssociation(ctx, l.resource, l.nextToken, l.pageSize)
	if err != nil {
		return err
	}
	l.Items = items
	l.nextToken = token
	return err
}

func (c *Client) ListNetworkFirewallPolicyAssociation(ctx context.Context, project, location, firewallPolicy string) (*NetworkFirewallPolicyAssociationList, error) {
	ctx = dcl.ContextWithRequestID(ctx)
	ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second))
	defer cancel()

	return c.ListNetworkFirewallPolicyAssociationWithMaxResults(ctx, project, location, firewallPolicy, NetworkFirewallPolicyAssociationMaxPage)

}

func (c *Client) ListNetworkFirewallPolicyAssociationWithMaxResults(ctx context.Context, project, location, firewallPolicy string, pageSize int32) (*NetworkFirewallPolicyAssociationList, error) {
	ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second))
	defer cancel()

	// Create a resource object so that we can use proper url normalization methods.
	r := &NetworkFirewallPolicyAssociation{
		Project:        &project,
		Location:       &location,
		FirewallPolicy: &firewallPolicy,
	}
	items, token, err := c.listNetworkFirewallPolicyAssociation(ctx, r, "", pageSize)
	if err != nil {
		return nil, err
	}
	return &NetworkFirewallPolicyAssociationList{
		Items:     items,
		nextToken: token,
		pageSize:  pageSize,
		resource:  r,
	}, nil
}

func (c *Client) GetNetworkFirewallPolicyAssociation(ctx context.Context, r *NetworkFirewallPolicyAssociation) (*NetworkFirewallPolicyAssociation, error) {
	ctx = dcl.ContextWithRequestID(ctx)
	ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second))
	defer cancel()

	// This is *purposefully* supressing errors.
	// This function is used with url-normalized values + not URL normalized values.
	// URL Normalized values will throw unintentional errors, since those values are not of the proper parent form.
	extractNetworkFirewallPolicyAssociationFields(r)

	b, err := c.getNetworkFirewallPolicyAssociationRaw(ctx, r)
	if err != nil {
		if dcl.IsNotFoundOrCode(err, 400) {
			return nil, &googleapi.Error{
				Code:    404,
				Message: err.Error(),
			}
		}
		return nil, err
	}
	result, err := unmarshalNetworkFirewallPolicyAssociation(b, c, r)
	if err != nil {
		return nil, err
	}
	result.Project = r.Project
	result.Location = r.Location
	result.FirewallPolicy = r.FirewallPolicy
	result.Name = r.Name

	c.Config.Logger.InfoWithContextf(ctx, "Retrieved raw result state: %v", result)
	c.Config.Logger.InfoWithContextf(ctx, "Canonicalizing with specified state: %v", r)
	result, err = canonicalizeNetworkFirewallPolicyAssociationNewState(c, result, r)
	if err != nil {
		return nil, err
	}
	if err := postReadExtractNetworkFirewallPolicyAssociationFields(result); err != nil {
		return result, err
	}
	c.Config.Logger.InfoWithContextf(ctx, "Created result state: %v", result)

	return result, nil
}

func (c *Client) DeleteNetworkFirewallPolicyAssociation(ctx context.Context, r *NetworkFirewallPolicyAssociation) error {
	ctx = dcl.ContextWithRequestID(ctx)
	ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second))
	defer cancel()

	if r == nil {
		return fmt.Errorf("NetworkFirewallPolicyAssociation resource is nil")
	}
	c.Config.Logger.InfoWithContext(ctx, "Deleting NetworkFirewallPolicyAssociation...")
	deleteOp := deleteNetworkFirewallPolicyAssociationOperation{}
	return deleteOp.do(ctx, r, c)
}

// DeleteAllNetworkFirewallPolicyAssociation deletes all resources that the filter functions returns true on.
func (c *Client) DeleteAllNetworkFirewallPolicyAssociation(ctx context.Context, project, location, firewallPolicy string, filter func(*NetworkFirewallPolicyAssociation) bool) error {
	listObj, err := c.ListNetworkFirewallPolicyAssociation(ctx, project, location, firewallPolicy)
	if err != nil {
		return err
	}

	err = c.deleteAllNetworkFirewallPolicyAssociation(ctx, filter, listObj.Items)
	if err != nil {
		return err
	}
	for listObj.HasNext() {
		err = listObj.Next(ctx, c)
		if err != nil {
			return nil
		}
		err = c.deleteAllNetworkFirewallPolicyAssociation(ctx, filter, listObj.Items)
		if err != nil {
			return err
		}
	}
	return nil
}

func (c *Client) ApplyNetworkFirewallPolicyAssociation(ctx context.Context, rawDesired *NetworkFirewallPolicyAssociation, opts ...dcl.ApplyOption) (*NetworkFirewallPolicyAssociation, error) {
	ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second))
	defer cancel()

	ctx = dcl.ContextWithRequestID(ctx)
	var resultNewState *NetworkFirewallPolicyAssociation
	err := dcl.Do(ctx, func(ctx context.Context) (*dcl.RetryDetails, error) {
		newState, err := applyNetworkFirewallPolicyAssociationHelper(c, ctx, rawDesired, opts...)
		resultNewState = newState
		if err != nil {
			// If the error is 409, there is conflict in resource update.
			// Here we want to apply changes based on latest state.
			if dcl.IsConflictError(err) {
				return &dcl.RetryDetails{}, dcl.OperationNotDone{Err: err}
			}
			return nil, err
		}
		return nil, nil
	}, c.Config.RetryProvider)
	return resultNewState, err
}

func applyNetworkFirewallPolicyAssociationHelper(c *Client, ctx context.Context, rawDesired *NetworkFirewallPolicyAssociation, opts ...dcl.ApplyOption) (*NetworkFirewallPolicyAssociation, error) {
	c.Config.Logger.InfoWithContext(ctx, "Beginning ApplyNetworkFirewallPolicyAssociation...")
	c.Config.Logger.InfoWithContextf(ctx, "User specified desired state: %v", rawDesired)

	// 1.1: Validation of user-specified fields in desired state.
	if err := rawDesired.validate(); err != nil {
		return nil, err
	}

	if err := extractNetworkFirewallPolicyAssociationFields(rawDesired); err != nil {
		return nil, err
	}

	initial, desired, fieldDiffs, err := c.networkFirewallPolicyAssociationDiffsForRawDesired(ctx, rawDesired, opts...)
	if err != nil {
		return nil, fmt.Errorf("failed to create a diff: %w", err)
	}

	diffs, err := convertFieldDiffsToNetworkFirewallPolicyAssociationDiffs(c.Config, fieldDiffs, opts)
	if err != nil {
		return nil, err
	}

	// TODO(magic-modules-eng): 2.2 Feasibility check (all updates are feasible so far).

	// 2.3: Lifecycle Directive Check
	var create bool
	lp := dcl.FetchLifecycleParams(opts)
	if initial == nil {
		if dcl.HasLifecycleParam(lp, dcl.BlockCreation) {
			return nil, dcl.ApplyInfeasibleError{Message: fmt.Sprintf("Creation blocked by lifecycle params: %#v.", desired)}
		}
		create = true
	} else if dcl.HasLifecycleParam(lp, dcl.BlockAcquire) {
		return nil, dcl.ApplyInfeasibleError{
			Message: fmt.Sprintf("Resource already exists - apply blocked by lifecycle params: %#v.", initial),
		}
	} else {
		for _, d := range diffs {
			if d.RequiresRecreate {
				return nil, dcl.ApplyInfeasibleError{
					Message: fmt.Sprintf("infeasible update: (%v) would require recreation", d),
				}
			}
			if dcl.HasLifecycleParam(lp, dcl.BlockModification) {
				return nil, dcl.ApplyInfeasibleError{Message: fmt.Sprintf("Modification blocked, diff (%v) unresolvable.", d)}
			}
		}
	}

	// 2.4 Imperative Request Planning
	var ops []networkFirewallPolicyAssociationApiOperation
	if create {
		ops = append(ops, &createNetworkFirewallPolicyAssociationOperation{})
	} else {
		for _, d := range diffs {
			ops = append(ops, d.UpdateOp)
		}
	}
	c.Config.Logger.InfoWithContextf(ctx, "Created plan: %#v", ops)

	// 2.5 Request Actuation
	for _, op := range ops {
		c.Config.Logger.InfoWithContextf(ctx, "Performing operation %T %+v", op, op)
		if err := op.do(ctx, desired, c); err != nil {
			c.Config.Logger.InfoWithContextf(ctx, "Failed operation %T %+v: %v", op, op, err)
			return nil, err
		}
		c.Config.Logger.InfoWithContextf(ctx, "Finished operation %T %+v", op, op)
	}
	return applyNetworkFirewallPolicyAssociationDiff(c, ctx, desired, rawDesired, ops, opts...)
}

func applyNetworkFirewallPolicyAssociationDiff(c *Client, ctx context.Context, desired *NetworkFirewallPolicyAssociation, rawDesired *NetworkFirewallPolicyAssociation, ops []networkFirewallPolicyAssociationApiOperation, opts ...dcl.ApplyOption) (*NetworkFirewallPolicyAssociation, error) {
	// 3.1, 3.2a Retrieval of raw new state & canonicalization with desired state
	c.Config.Logger.InfoWithContext(ctx, "Retrieving raw new state...")
	rawNew, err := c.GetNetworkFirewallPolicyAssociation(ctx, desired)
	if err != nil {
		return nil, err
	}
	// Get additional values from the first response.
	// These values should be merged into the newState above.
	if len(ops) > 0 {
		lastOp := ops[len(ops)-1]
		if o, ok := lastOp.(*createNetworkFirewallPolicyAssociationOperation); ok {
			if r, hasR := o.FirstResponse(); hasR {

				c.Config.Logger.InfoWithContext(ctx, "Retrieving raw new state from operation...")

				fullResp, err := unmarshalMapNetworkFirewallPolicyAssociation(r, c, rawDesired)
				if err != nil {
					return nil, err
				}

				rawNew, err = canonicalizeNetworkFirewallPolicyAssociationNewState(c, rawNew, fullResp)
				if err != nil {
					return nil, err
				}
			}
		}
	}

	c.Config.Logger.InfoWithContextf(ctx, "Canonicalizing with raw desired state: %v", rawDesired)
	// 3.2b Canonicalization of raw new state using raw desired state
	newState, err := canonicalizeNetworkFirewallPolicyAssociationNewState(c, rawNew, rawDesired)
	if err != nil {
		return rawNew, err
	}

	c.Config.Logger.InfoWithContextf(ctx, "Created canonical new state: %v", newState)
	// 3.3 Comparison of the new state and raw desired state.
	// TODO(magic-modules-eng): EVENTUALLY_CONSISTENT_UPDATE
	newDesired, err := canonicalizeNetworkFirewallPolicyAssociationDesiredState(rawDesired, newState)
	if err != nil {
		return newState, err
	}

	if err := postReadExtractNetworkFirewallPolicyAssociationFields(newState); err != nil {
		return newState, err
	}

	// Need to ensure any transformations made here match acceptably in differ.
	if err := postReadExtractNetworkFirewallPolicyAssociationFields(newDesired); err != nil {
		return newState, err
	}

	c.Config.Logger.InfoWithContextf(ctx, "Diffing using canonicalized desired state: %v", newDesired)
	newDiffs, err := diffNetworkFirewallPolicyAssociation(c, newDesired, newState)
	if err != nil {
		return newState, err
	}

	if len(newDiffs) == 0 {
		c.Config.Logger.InfoWithContext(ctx, "No diffs found. Apply was successful.")
	} else {
		c.Config.Logger.InfoWithContextf(ctx, "Found diffs: %v", newDiffs)
		diffMessages := make([]string, len(newDiffs))
		for i, d := range newDiffs {
			diffMessages[i] = fmt.Sprintf("%v", d)
		}
		return newState, dcl.DiffAfterApplyError{Diffs: diffMessages}
	}
	c.Config.Logger.InfoWithContext(ctx, "Done Apply.")
	return newState, nil
}


text:
using System.Collections.Generic;
using System.Xml.Serialization;

namespace Nez.TiledMaps
{
	public class TmxTerrain
	{
		[XmlAttribute( AttributeName = "name" )]
		public string name;

		[XmlAttribute( AttributeName = "tile" )]
		public int tileId;

		[XmlArray( "properties" )]
		[XmlArrayItem( "property" )]
		public List<TmxProperty> properties = new List<TmxProperty>();

		public override string ToString()
		{
			return name;
		}
	}
}


text:
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="dataSourceStorageLocal">
    <data-source name="MySQL - joystudy@localhost" uuid="7001328d-5e09-4e63-a2c5-3ce29ec77472">
      <secret-storage>master_key</secret-storage>
      <user-name>root</user-name>
      <schema-pattern>joystudy.*</schema-pattern>
      <default-schemas>joystudy.*</default-schemas>
    </data-source>
  </component>
</project>


text:
<!DOCTYPE html>

  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>some writings from a humblelistener</title>
  <meta name="author" content="P Karthikeyan">
  <meta name="description" content="">
  <meta property="og:title" content="some writings from a humblelistener">
  <meta property="og:url" content="https://humblelistener.github.io/">
  <meta property="og:site_name" content="some writings from a humblelistener">
  <meta property="og:description" content="">
  <meta property="og:image" content="">
  <meta property="og:type" content="blog">

  <meta name="twitter:card" content="summary">
  <meta name="twitter:description" content="">
  <meta name="twitter:title" content="some writings from a humblelistener">
  <meta name="twitter:url" content="https://humblelistener.github.io/">
  <meta name="twitter:site" content="some writings from a humblelistener">
  <meta name="twitter:creator" content="@@humblelistener">
  <meta name="twitter:domain" content="https://humblelistener.github.io">
  <meta property="twitter:image" content="">

  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inconsolata|Lora|Space+Mono:700">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.min.css">
  <link rel="stylesheet" href="/assets/css/main.css">

  <link rel="alternate" type="application/rss+xml" title="some writings from a humblelistener" href="https://humblelistener.github.io/feed.xml">
  <link rel="canonical" href="https://humblelistener.github.io/">

      Welcome to

some writings from a humblelistener

Posts

Categories

              May 23, 2018

Recipe for High-Performance Teams

High-Performance Teams Recently on LinkedIn, one of my past colleagues posted a question that made me share my beliefs and learnings from being part of as well as creating, tendering...

              Read More

              Jul 10, 2017

Organisations existence

Organisations existence Most of the organisations seem to exist to fill the gap in helping people and world solve a particular problem - if it is not an obvious problem,...

              Read More

              Jun 11, 2017

Beta Environment configuration on AWS

BETA Environment configuration for large scale application hosted on AWS This is in continuation to the previous post, I wrote about a situation where it was getting hard to deploy...

              Read More

              May 4, 2017

What do you do when you lose confidence in code?

What do you do when you lose confidence in code? This is happening to me. One of the inherited product I have is so complex that investing time and money...

              Read More

              Apr 4, 2017

Psychological safety - Building high performance team

Psychological safety Building high performance team series Before I realized, my interest in software engineering and building quality software lead me to having a passion in building high performance team....

              Read More

            Next

  Archive

A/B

0 Posts

            View All

AB

0 Posts

            View All

AWS

0 Posts

            View All

Beta

0 Posts

            View All

Beta

0 Posts

            View All

Solution

0 Posts

            View All

Traffic

0 Posts

            View All

c#

2 Posts

            View All

career

1 Posts

            View All

continuous-deployment

1 Posts

            View All

continuous-integration

1 Posts

            View All

design

0 Posts

            View All

engineering

0 Posts

            View All

high-performance-team

1 Posts

            View All

leadership

1 Posts

            View All

mission

0 Posts

            View All

organisation

0 Posts

            View All

organisation

0 Posts

            View All

programming

8 Posts

            View All

software

0 Posts

            View All

software

0 Posts

            View All

splitting

0 Posts

            View All

teams

1 Posts

            View All

testing

0 Posts

            View All

testing

0 Posts

            View All

testing

0 Posts

            View All

testing

0 Posts

            View All

testing

0 Posts

            View All

travis-ci

1 Posts

            View All

vision

0 Posts

            View All

  Archive