<commit_before>#!/usr/bin/env python
#
# Copyright 2017 GoPro Inc.
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

import sys
from xml.etree import ElementTree as ET

cmds_optional = [
    # Framebuffer
    'glBlitFramebuffer',
    'glInvalidateFramebuffer',

    # Renderbuffer
    'glRenderbufferStorageMultisample',

    # Texture
    'glTexImage3D',
    'glTexStorage2D',
    'glTexStorage3D',
    'glTexSubImage3D',
    'glBindImageTexture',

    # Vertex Arrays
    'glBindVertexArray',
    'glDeleteVertexArrays',
    'glGenVertexArrays',

    # Barrier
    'glMemoryBarrier',

    #  Buffers
    'glBindBufferBase',
    'glBindBufferRange',

    # Compute shaders
    'glDispatchCompute',

    # Shaders
    'glGetProgramResourceLocation',
    'glGetProgramResourceIndex',
    'glGetProgramResourceiv',
    'glGetProgramInterfaceiv',
    'glGetProgramResourceName',

    # Polygon
    'glPolygonMode',

    # Internal format
    'glGetInternalformativ',

    # Query
    'glBeginQuery',
    'glEndQuery',
    'glGenQueries',
    'glDeleteQueries',
    'glQueryCounter',
    'glGetQueryObjectui64v',

    # Debug
    'glDebugMessageCallback',

    # Query EXT
    'glBeginQueryEXT',
    'glEndQueryEXT',
    'glGenQueriesEXT',
    'glDeleteQueriesEXT',
    'glQueryCounterEXT',
    'glGetQueryObjectui64vEXT',

    # Instancing
    'glDrawArraysInstanced',
    'glDrawElementsInstanced',
    'glVertexAttribDivisor',

    # Uniform Block Object
    'glGetUniformBlockIndex',
    'glUniformBlockBinding',
    'glGetActiveUniformBlockName',
    'glGetActiveUniformBlockiv',

    # EGL OES image
    'glEGLImageTargetTexture2DOES',

    # Sync object
    'glFenceSync',
    'glWaitSync',
    'glClientWaitSync',

    # Read/Draw Buffer
    'glReadBuffer',
    'glDrawBuffer',
    'glDrawBuffers',

    # Clear Buffer
    'glClearBufferfv',
    'glClearBufferfi',

    # UInt uniforms
    'glUniform1uiv',
    'glUniform2uiv',
    'glUniform3uiv',
    'glUniform4uiv',
]

cmds = [
    # Enable
    'glEnable',
    'glDisable',

    # Error
    'glGetError',

    # Get
    'glGetBooleanv',
    'glGetIntegeri_v',
    'glGetIntegerv',
    'glGetString',
    'glGetStringi',

    # Viewport
    'glViewport',
    'glScissor',

    # Color
    'glColorMask',

    # Depth
    'glDepthFunc',
    'glDepthMask',

    # Clear
    'glClear',
    'glClearColor',

    # Blending
    'glBlendColor',
    'glBlendEquation',
    'glBlendEquationSeparate',
    'glBlendFunc',
    'glBlendFuncSeparate',

    # Draw
    'glDrawArrays',
    'glDrawElements',

    # Texture
    'glActiveTexture',
    'glBindTexture',
    'glDeleteTextures',
    'glGenTextures',
    'glGenerateMipmap',
    'glPixelStorei',
    'glTexImage2D',
    'glTexParameteri',
    'glTexSubImage2D',

    # Framebuffer
    'glCheckFramebufferStatus',
    'glBindFramebuffer',
    'glDeleteFramebuffers',
    'glFramebufferRenderbuffer',
    'glFramebufferTexture2D',
    'glGenFramebuffers',
    'glReadPixels',

    # Buffer
    'glBindBuffer',
    'glBufferData',
    'glBufferSubData',
    'glDeleteBuffers',
    'glGenBuffers',

    # Render buffer
    'glBindRenderbuffer',
    'glDeleteRenderbuffers',
    'glGenRenderbuffers',
    'glGetRenderbufferParameteriv',
    'glRenderbufferStorage',

    # Shader
    'glCreateProgram',
    'glCreateShader',
    'glAttachShader',
    'glCompileShader',
    'glDeleteProgram',
    'glDeleteShader',
    'glDetachShader',
    'glGetAttachedShaders',
    'glGetProgramInfoLog',
    'glGetProgramiv',
    'glGetShaderInfoLog',
    'glGetShaderSource',
    'glGetShaderiv',
    'glLinkProgram',
    'glReleaseShaderCompiler',
    'glShaderBinary',
    'glShaderSource',
    'glUseProgram',

    # Shader Attributes
    'glGetAttribLocation',
    'glBindAttribLocation',
    'glEnableVertexAttribArray',
    'glDisableVertexAttribArray',
    'glVertexAttribPointer',
    'glGetActiveAttrib',
    'glGetActiveUniform',

    # Shader Uniforms
    'glGetUniformLocation',
    'glGetUniformiv',
    'glUniform1fv',
    'glUniform1i',
    'glUniform1iv',
    'glUniform2fv',
    'glUniform2iv',
    'glUniform3fv',
    'glUniform3iv',
    'glUniform4fv',
    'glUniform4iv',
    'glUniformMatrix2fv',
    'glUniformMatrix3fv',
    'glUniformMatrix4fv',

    # Stencil
    'glStencilFunc',
    'glStencilFuncSeparate',
    'glStencilMask',
    'glStencilMaskSeparate',
    'glStencilOp',
    'glStencilOpSeparate',

    # Face Culling
    'glCullFace',

    # Sync
    'glFlush',
    'glFinish',

] + cmds_optional

def get_proto_elems(xml_node):
    elems = []
    for text in xml_node.itertext():
        text = text.strip()
        if not text:
            continue
        elems.append(text)
    return elems

def gen(gl_xml, func_file, def_file, wrap_file):

    do_not_edit = '/* DO NOT EDIT - This file is autogenerated */\n'

    glwrappers = do_not_edit + '''
/* WARNING: this file must only be included once */

#include "config.h"

#if DEBUG_GL
# define check_error_code ngli_glcontext_check_gl_error
#else
# define check_error_code(gl, glfuncname) do { } while (0)
#endif
'''

    glfunctions = do_not_edit + '''
#ifndef NGL_GLFUNCS_H
#define NGL_GLFUNCS_H

#include "glincludes.h"

struct glfunctions {
'''

    gldefinitions = do_not_edit + '''
/* WARNING: this file must only be included once */

#include <stddef.h>

#include "glcontext.h"

#define M (1 << 0)

static const struct gldefinition {
    const char *name;
    size_t offset;
    int flags;
} gldefinitions[] = {
'''

    xml = ET.parse(gl_xml)
    root = xml.getroot()
    commands = root.find('commands')
    for cmd in commands:
        proto = cmd.find('proto')
        funcname = proto.find('name').text

        if funcname not in cmds:
            continue

        ptype = proto.find('ptype')
        funcret = ' '.join(get_proto_elems(proto)[:-1])

        ret_assign = ''
        ret_call = ''
        if funcret != 'void':
            ret_assign = '%s ret = ' % funcret
            ret_call = '    return ret;\n'

        func_args_specs = []
        func_args = []
        for param in cmd.findall('param'):
            func_args_specs.append(' '.join(get_proto_elems(param)))
            func_args.append(param.find('name').text)

        wrapper_args_specs = ['const struct glcontext *gl'] + func_args_specs

        data = {
                'func_ret': funcret,
                'func_name': funcname,
                'func_name_nogl': funcname[2:], # with "gl" stripped
                'wrapper_args_specs': ', '.join(wrapper_args_specs),
                'func_args_specs': ', '.join(func_args_specs),
                'ret_assign': ret_assign,
                'func_args': ', '.join(func_args),
                'ret_call': ret_call,
                'flags': '0' if funcname in cmds_optional else 'M',
        }

        glfunctions   += '    %(func_ret)s (NGLI_GL_APIENTRY *%(func_name_nogl)s)(%(func_args_specs)s);\n' % data
        gldefinitions += '    {"%(func_name)s", offsetof(struct glfunctions, %(func_name_nogl)s), %(flags)s},\n' % data
        if funcname == 'glGetError':
            glwrappers += '''
static inline GLenum ngli_glGetError(const struct glcontext *gl)
{
    return gl->funcs.GetError();
}
'''
        else:
            glwrappers    += '''
static inline %(func_ret)s ngli_%(func_name)s(%(wrapper_args_specs)s)
{
    %(ret_assign)sgl->funcs.%(func_name_nogl)s(%(func_args)s);
    check_error_code(gl, "%(func_name)s");
%(ret_call)s}
''' % data

        cmds.pop(cmds.index(funcname))
        if not cmds:
            break

    if cmds:
        print('WARNING: function(s) not found: ' + ', '.join(cmds))

    glfunctions   += '};\n\n#endif\n'
    gldefinitions += '};\n'

    with open(func_file, 'w') as f:
        f.write(glfunctions)
    with open(def_file, 'w') as f:
        f.write(gldefinitions)
    with open(wrap_file, 'w') as f:
        f.write(glwrappers)

if __name__ == '__main__':
    if len(sys.argv) != 5:
        print('Usage: %s <gl.xml> <func.h> <def.h> <wrap.h>' % sys.argv[0])
        sys.exit(0)
    gen(*sys.argv[1:])
<commit_msg>gl: use unix-style line endings when generating gl headers<commit_after>#!/usr/bin/env python
#
# Copyright 2017 GoPro Inc.
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

import sys
from xml.etree import ElementTree as ET

cmds_optional = [
    # Framebuffer
    'glBlitFramebuffer',
    'glInvalidateFramebuffer',

    # Renderbuffer
    'glRenderbufferStorageMultisample',

    # Texture
    'glTexImage3D',
    'glTexStorage2D',
    'glTexStorage3D',
    'glTexSubImage3D',
    'glBindImageTexture',

    # Vertex Arrays
    'glBindVertexArray',
    'glDeleteVertexArrays',
    'glGenVertexArrays',

    # Barrier
    'glMemoryBarrier',

    #  Buffers
    'glBindBufferBase',
    'glBindBufferRange',

    # Compute shaders
    'glDispatchCompute',

    # Shaders
    'glGetProgramResourceLocation',
    'glGetProgramResourceIndex',
    'glGetProgramResourceiv',
    'glGetProgramInterfaceiv',
    'glGetProgramResourceName',

    # Polygon
    'glPolygonMode',

    # Internal format
    'glGetInternalformativ',

    # Query
    'glBeginQuery',
    'glEndQuery',
    'glGenQueries',
    'glDeleteQueries',
    'glQueryCounter',
    'glGetQueryObjectui64v',

    # Debug
    'glDebugMessageCallback',

    # Query EXT
    'glBeginQueryEXT',
    'glEndQueryEXT',
    'glGenQueriesEXT',
    'glDeleteQueriesEXT',
    'glQueryCounterEXT',
    'glGetQueryObjectui64vEXT',

    # Instancing
    'glDrawArraysInstanced',
    'glDrawElementsInstanced',
    'glVertexAttribDivisor',

    # Uniform Block Object
    'glGetUniformBlockIndex',
    'glUniformBlockBinding',
    'glGetActiveUniformBlockName',
    'glGetActiveUniformBlockiv',

    # EGL OES image
    'glEGLImageTargetTexture2DOES',

    # Sync object
    'glFenceSync',
    'glWaitSync',
    'glClientWaitSync',

    # Read/Draw Buffer
    'glReadBuffer',
    'glDrawBuffer',
    'glDrawBuffers',

    # Clear Buffer
    'glClearBufferfv',
    'glClearBufferfi',

    # UInt uniforms
    'glUniform1uiv',
    'glUniform2uiv',
    'glUniform3uiv',
    'glUniform4uiv',
]

cmds = [
    # Enable
    'glEnable',
    'glDisable',

    # Error
    'glGetError',

    # Get
    'glGetBooleanv',
    'glGetIntegeri_v',
    'glGetIntegerv',
    'glGetString',
    'glGetStringi',

    # Viewport
    'glViewport',
    'glScissor',

    # Color
    'glColorMask',

    # Depth
    'glDepthFunc',
    'glDepthMask',

    # Clear
    'glClear',
    'glClearColor',

    # Blending
    'glBlendColor',
    'glBlendEquation',
    'glBlendEquationSeparate',
    'glBlendFunc',
    'glBlendFuncSeparate',

    # Draw
    'glDrawArrays',
    'glDrawElements',

    # Texture
    'glActiveTexture',
    'glBindTexture',
    'glDeleteTextures',
    'glGenTextures',
    'glGenerateMipmap',
    'glPixelStorei',
    'glTexImage2D',
    'glTexParameteri',
    'glTexSubImage2D',

    # Framebuffer
    'glCheckFramebufferStatus',
    'glBindFramebuffer',
    'glDeleteFramebuffers',
    'glFramebufferRenderbuffer',
    'glFramebufferTexture2D',
    'glGenFramebuffers',
    'glReadPixels',

    # Buffer
    'glBindBuffer',
    'glBufferData',
    'glBufferSubData',
    'glDeleteBuffers',
    'glGenBuffers',

    # Render buffer
    'glBindRenderbuffer',
    'glDeleteRenderbuffers',
    'glGenRenderbuffers',
    'glGetRenderbufferParameteriv',
    'glRenderbufferStorage',

    # Shader
    'glCreateProgram',
    'glCreateShader',
    'glAttachShader',
    'glCompileShader',
    'glDeleteProgram',
    'glDeleteShader',
    'glDetachShader',
    'glGetAttachedShaders',
    'glGetProgramInfoLog',
    'glGetProgramiv',
    'glGetShaderInfoLog',
    'glGetShaderSource',
    'glGetShaderiv',
    'glLinkProgram',
    'glReleaseShaderCompiler',
    'glShaderBinary',
    'glShaderSource',
    'glUseProgram',

    # Shader Attributes
    'glGetAttribLocation',
    'glBindAttribLocation',
    'glEnableVertexAttribArray',
    'glDisableVertexAttribArray',
    'glVertexAttribPointer',
    'glGetActiveAttrib',
    'glGetActiveUniform',

    # Shader Uniforms
    'glGetUniformLocation',
    'glGetUniformiv',
    'glUniform1fv',
    'glUniform1i',
    'glUniform1iv',
    'glUniform2fv',
    'glUniform2iv',
    'glUniform3fv',
    'glUniform3iv',
    'glUniform4fv',
    'glUniform4iv',
    'glUniformMatrix2fv',
    'glUniformMatrix3fv',
    'glUniformMatrix4fv',

    # Stencil
    'glStencilFunc',
    'glStencilFuncSeparate',
    'glStencilMask',
    'glStencilMaskSeparate',
    'glStencilOp',
    'glStencilOpSeparate',

    # Face Culling
    'glCullFace',

    # Sync
    'glFlush',
    'glFinish',

] + cmds_optional

def get_proto_elems(xml_node):
    elems = []
    for text in xml_node.itertext():
        text = text.strip()
        if not text:
            continue
        elems.append(text)
    return elems

def gen(gl_xml, func_file, def_file, wrap_file):

    do_not_edit = '/* DO NOT EDIT - This file is autogenerated */\n'

    glwrappers = do_not_edit + '''
/* WARNING: this file must only be included once */

#include "config.h"

#if DEBUG_GL
# define check_error_code ngli_glcontext_check_gl_error
#else
# define check_error_code(gl, glfuncname) do { } while (0)
#endif
'''

    glfunctions = do_not_edit + '''
#ifndef NGL_GLFUNCS_H
#define NGL_GLFUNCS_H

#include "glincludes.h"

struct glfunctions {
'''

    gldefinitions = do_not_edit + '''
/* WARNING: this file must only be included once */

#include <stddef.h>

#include "glcontext.h"

#define M (1 << 0)

static const struct gldefinition {
    const char *name;
    size_t offset;
    int flags;
} gldefinitions[] = {
'''

    xml = ET.parse(gl_xml)
    root = xml.getroot()
    commands = root.find('commands')
    for cmd in commands:
        proto = cmd.find('proto')
        funcname = proto.find('name').text

        if funcname not in cmds:
            continue

        ptype = proto.find('ptype')
        funcret = ' '.join(get_proto_elems(proto)[:-1])

        ret_assign = ''
        ret_call = ''
        if funcret != 'void':
            ret_assign = '%s ret = ' % funcret
            ret_call = '    return ret;\n'

        func_args_specs = []
        func_args = []
        for param in cmd.findall('param'):
            func_args_specs.append(' '.join(get_proto_elems(param)))
            func_args.append(param.find('name').text)

        wrapper_args_specs = ['const struct glcontext *gl'] + func_args_specs

        data = {
                'func_ret': funcret,
                'func_name': funcname,
                'func_name_nogl': funcname[2:], # with "gl" stripped
                'wrapper_args_specs': ', '.join(wrapper_args_specs),
                'func_args_specs': ', '.join(func_args_specs),
                'ret_assign': ret_assign,
                'func_args': ', '.join(func_args),
                'ret_call': ret_call,
                'flags': '0' if funcname in cmds_optional else 'M',
        }

        glfunctions   += '    %(func_ret)s (NGLI_GL_APIENTRY *%(func_name_nogl)s)(%(func_args_specs)s);\n' % data
        gldefinitions += '    {"%(func_name)s", offsetof(struct glfunctions, %(func_name_nogl)s), %(flags)s},\n' % data
        if funcname == 'glGetError':
            glwrappers += '''
static inline GLenum ngli_glGetError(const struct glcontext *gl)
{
    return gl->funcs.GetError();
}
'''
        else:
            glwrappers    += '''
static inline %(func_ret)s ngli_%(func_name)s(%(wrapper_args_specs)s)
{
    %(ret_assign)sgl->funcs.%(func_name_nogl)s(%(func_args)s);
    check_error_code(gl, "%(func_name)s");
%(ret_call)s}
''' % data

        cmds.pop(cmds.index(funcname))
        if not cmds:
            break

    if cmds:
        print('WARNING: function(s) not found: ' + ', '.join(cmds))

    glfunctions   += '};\n\n#endif\n'
    gldefinitions += '};\n'

    with open(func_file, 'w', newline='\n') as f:
        f.write(glfunctions)
    with open(def_file, 'w', newline='\n') as f:
        f.write(gldefinitions)
    with open(wrap_file, 'w', newline='\n') as f:
        f.write(glwrappers)

if __name__ == '__main__':
    if len(sys.argv) != 5:
        print('Usage: %s <gl.xml> <func.h> <def.h> <wrap.h>' % sys.argv[0])
        sys.exit(0)
    gen(*sys.argv[1:])
<|endoftext|>


<commit_before>#!/usr/bin/env python3
import httplib2
import json
import random

def doRequest(http,url, algSuffix, request):
   headers ={'Content-Type':'application/json', "Accept":"application/json"}
   resp, content = http.request(uri=url+"/alg"+algSuffix, method="POST", body=json.dumps(request))
   if resp['status'] == '200':
      return True, json.loads(str(content, "UTF-8"))
   else:
      return False, json.loads(str(content, "UTF-8"))

def main():
   http = httplib2.Http()
   request = {'points':[{'lt': 487786110, 'ln' : 91794440}, {'lt': 535652780, 'ln': 100013890}]}
   random.seed(42)
   for i in range(1, 1000):
      points = []
      for i in range(0, 2):
         lat = random.randint(472600000, 548960000)
         lon = random.randint( 59000000, 149900000)
         points.append({'lt': lat, 'ln' : lon})

      request['points'] = points
      success, content = doRequest(http, 'http://localhost:8080', 'sp', request)
      if not success:
         print('Failed: '+content)
      else:
         print('Distance: '+str(content['misc']['distance']/1000.0))

if __name__ == "__main__":
   main()
<commit_msg>Configuration for testing tsp<commit_after>#!/usr/bin/env python3
import httplib2
import json
import random

def doRequest(http,url, algSuffix, request):
   headers ={'Content-Type':'application/json', "Accept":"application/json"}
   resp, content = http.request(uri=url+"/alg"+algSuffix, method="POST", body=json.dumps(request))
   if resp['status'] == '200':
      return True, json.loads(str(content, "UTF-8"))
   else:
      return False, json.loads(str(content, "UTF-8"))

def main():
   http = httplib2.Http()
   request = {'points':[{'lt': 487786110, 'ln' : 91794440}, {'lt': 535652780, 'ln': 100013890}]}
   random.seed(42)
   for i in range(0, 10):
      points = []
      for i in range(0, 16):
         lat = random.randint(472600000, 548960000)
         lon = random.randint( 59000000, 149900000)
         points.append({'lt': lat, 'ln' : lon})

      request['points'] = points
      success, content = doRequest(http, 'http://localhost:8080', 'tsp', request)
      if not success:
         print('Failed: '+content)
      else:
         print(str(content['misc']['distance']/1000.0))

if __name__ == "__main__":
   main()
<|endoftext|>


<commit_before>#!/usr/bin/python3

# written by sqall
# twitter: https://twitter.com/sqall01
# blog: https://h4des.org
# github: https://github.com/sqall01
#
# Licensed under the GNU Affero General Public License, version 3.

import copy
from typing import Optional, List, Any, Dict

class InternalState:
    NOT_USED = 0
    STORED = 1
    DELETED = 2

# This enum class gives the different data types of a sensor.
class SensorDataType:
    NONE = 0
    INT = 1
    FLOAT = 2

class LocalObject:

    def __init__(self):
        # Internal data used by the manager.
        self.internal_state = InternalState.NOT_USED
        self.internal_data = dict()

    def is_deleted(self):
        return self.internal_state == InternalState.DELETED

    def is_stored(self):
        return self.internal_state == InternalState.STORED

    def deepcopy(self, obj):
        raise NotImplementedError("Abstract class.")

# this class represents an option of the server
class Option(LocalObject):

    def __init__(self):
        super().__init__()
        self.type = None  # type: Optional[str]
        self.value = None  # type: Optional[float]

    def deepcopy(self, option):
        self.type = option.type
        self.value = option.value
        return self

# this class represents an node/client of the alert system
# which can be either a sensor, alert or manager
class Node(LocalObject):

    def __init__(self):
        super().__init__()
        self.nodeId = None  # type: Optional[int]
        self.hostname = None  # type: Optional[str]
        self.nodeType = None  # type: Optional[str]
        self.instance = None  # type: Optional[str]
        self.connected = None  # type: Optional[int]
        self.version = None  # type: Optional[float]
        self.rev = None  # type: Optional[int]
        self.username = None  # type: Optional[str]
        self.persistent = None  # type: Optional[int]

    # This function copies all attributes of the given node to this object.
    def deepcopy(self, node):
        self.nodeId = node.nodeId
        self.hostname = node.hostname
        self.nodeType = node.nodeType
        self.instance = node.instance
        self.connected = node.connected
        self.version = node.version
        self.rev = node.rev
        self.username = node.username
        self.persistent = node.persistent
        return self

# this class represents a sensor client of the alert system
class Sensor(LocalObject):

    def __init__(self):
        super().__init__()
        self.nodeId = None  # type: Optional[int]
        self.sensorId = None  # type: Optional[int]
        self.remoteSensorId = None  # type: Optional[int]
        self.alertDelay = None  # type: Optional[int]
        self.alertLevels = list()  # type: List[int]
        self.description = None  # type: Optional[str]
        self.lastStateUpdated = None  # type: Optional[int]
        self.state = None  # type: Optional[int]
        self.dataType = None  # type: Optional[int]
        self.data = None  # type: Any

    # This function copies all attributes of the given sensor to this object.
    def deepcopy(self, sensor):
        self.nodeId = sensor.nodeId
        self.sensorId = sensor.sensorId
        self.remoteSensorId = sensor.remoteSensorId
        self.alertDelay = sensor.alertDelay
        self.alertLevels = list(sensor.alertLevels)
        self.description = sensor.description
        self.lastStateUpdated = sensor.lastStateUpdated
        self.state = sensor.state
        self.dataType = sensor.dataType
        self.data = sensor.data
        return self

# this class represents a manager client of the alert system
class Manager(LocalObject):

    def __init__(self):
        super().__init__()
        self.nodeId = None  # type: Optional[int]
        self.managerId = None  # type: Optional[int]
        self.description = None  # type: Optional[str]

    # This function copies all attributes of the given manager to this object.
    def deepcopy(self, manager):
        self.nodeId = manager.nodeId
        self.managerId = manager.managerId
        self.description = manager.description
        return self

# this class represents an alert client of the alert system
class Alert(LocalObject):

    def __init__(self):
        super().__init__()
        self.nodeId = None  # type: Optional[int]
        self.alertId = None  # type: Optional[int]
        self.remoteAlertId = None  # type: Optional[int]
        self.alertLevels = list()  # type: List[int]
        self.description = None  # type: Optional[str]

    # This function copies all attributes of the given alert to this object.
    def deepcopy(self, alert):
        self.nodeId = alert.nodeId
        self.alertId = alert.alertId
        self.remoteAlertId = alert.remoteAlertId
        self.alertLevels = list(alert.alertLevels)
        self.description = alert.description
        return self

# this class represents a triggered sensor alert of the alert system
class SensorAlert(LocalObject):

    def __init__(self):
        super().__init__()

        self.sensorId = None  # type: Optional[int]

        # State of the sensor alert ("triggered" = 1; "normal" = 0).
        self.state = None  # type: Optional[int]

        # Description of the sensor that raised this sensor alert.
        self.description = None  # type: Optional[str]

        # Time this sensor alert was received.
        self.timeReceived = None  # type: Optional[int]

        # List of alert levels (Integer) that are triggered
        # by this sensor alert.
        self.alertLevels = list()  # type: List[int]

        # The optional data of the sensor alert (if it has any).
        self.hasOptionalData = None  # type: Optional[bool]
        self.optionalData = None  # type: Dict[str, Any]

        # Does this sensor alert change the state of the sensor?
        self.changeState = None  # type: Optional[bool]

        # Does this sensor alert hold the latest data of the sensor?
        self.hasLatestData = None  # type: Optional[bool]

        # The sensor data type and data that is connected to this sensor alert.
        self.dataType = None  # type: Optional[int]
        self.sensorData = None  # type: Any

    def __str__(self):
        tmp = "Sensor Alert (Description: '%s'; " \
              % self.description \
              + "SensorID: %s; " \
              % str(self.sensorId) if self.sensorId is not None else "None" \
              + "State: %s; " \
              % str(self.state) if self.state is not None else "None" \
              + "Time Received: %s; " \
              % str(self.timeReceived) if self.timeReceived is not None else "None" \
              + "Alert Levels: %s)" \
              % ", ".join(map(str, self.alertLevels))
        return tmp

    # This function copies all attributes of the given sensor alert to this object.
    def deepcopy(self, sensor_alert):
        self.sensorId = sensor_alert.sensorId
        self.state = sensor_alert.state
        self.description = sensor_alert.description
        self.timeReceived = sensor_alert.timeReceived
        self.alertLevels = list(sensor_alert.alertLevels)
        self.hasOptionalData = sensor_alert.hasOptionalData
        self.changeState = sensor_alert.changeState
        self.hasLatestData = sensor_alert.hasLatestData
        self.dataType = sensor_alert.dataType
        self.sensorData = sensor_alert.sensorData

        if type(sensor_alert.optionalData) == dict:
            self.optionalData = copy.deepcopy(sensor_alert.optionalData)

        else:
            self.optionalData = None

        return self

# this class represents an alert level that is configured on the server
class AlertLevel(LocalObject):

    def __init__(self):
        super().__init__()
        self.level = None  # type: Optional[int]
        self.name = None  # type: Optional[str]
        self.triggerAlways = None  # type: Optional[int]
        self.instrumentation_active = None  # type: Optional[bool]
        self.instrumentation_cmd = None  # type: Optional[str]
        self.instrumentation_timeout = None  # type: Optional[int]

    # This function copies all attributes of the given alert level to this object.
    def deepcopy(self, alert_level):
        self.level = alert_level.level
        self.name = alert_level.name
        self.triggerAlways = alert_level.triggerAlways
        self.instrumentation_active = alert_level.instrumentation_active
        if self.instrumentation_active:
            self.instrumentation_cmd = alert_level.instrumentation_cmd
            self.instrumentation_timeout = alert_level.instrumentation_timeout

        else:
            self.instrumentation_cmd = None
            self.instrumentation_timeout = None
        return self
<commit_msg>added lock for multi-threaded programs<commit_after>#!/usr/bin/python3

# written by sqall
# twitter: https://twitter.com/sqall01
# blog: https://h4des.org
# github: https://github.com/sqall01
#
# Licensed under the GNU Affero General Public License, version 3.

import copy
import threading
from typing import Optional, List, Any, Dict

class InternalState:
    NOT_USED = 0
    STORED = 1
    DELETED = 2

# This enum class gives the different data types of a sensor.
class SensorDataType:
    NONE = 0
    INT = 1
    FLOAT = 2

class LocalObject:

    def __init__(self):
        # Internal data used by the manager.
        self.internal_state = InternalState.NOT_USED
        self.internal_data = dict()

        # To lock internal data structure if necessary for multi threaded programs.
        self.internal_data_lock = threading.Lock()

    def is_deleted(self):
        return self.internal_state == InternalState.DELETED

    def is_stored(self):
        return self.internal_state == InternalState.STORED

    def deepcopy(self, obj):
        raise NotImplementedError("Abstract class.")

# this class represents an option of the server
class Option(LocalObject):

    def __init__(self):
        super().__init__()
        self.type = None  # type: Optional[str]
        self.value = None  # type: Optional[float]

    def deepcopy(self, option):
        self.type = option.type
        self.value = option.value
        return self

# this class represents an node/client of the alert system
# which can be either a sensor, alert or manager
class Node(LocalObject):

    def __init__(self):
        super().__init__()
        self.nodeId = None  # type: Optional[int]
        self.hostname = None  # type: Optional[str]
        self.nodeType = None  # type: Optional[str]
        self.instance = None  # type: Optional[str]
        self.connected = None  # type: Optional[int]
        self.version = None  # type: Optional[float]
        self.rev = None  # type: Optional[int]
        self.username = None  # type: Optional[str]
        self.persistent = None  # type: Optional[int]

    # This function copies all attributes of the given node to this object.
    def deepcopy(self, node):
        self.nodeId = node.nodeId
        self.hostname = node.hostname
        self.nodeType = node.nodeType
        self.instance = node.instance
        self.connected = node.connected
        self.version = node.version
        self.rev = node.rev
        self.username = node.username
        self.persistent = node.persistent
        return self

# this class represents a sensor client of the alert system
class Sensor(LocalObject):

    def __init__(self):
        super().__init__()
        self.nodeId = None  # type: Optional[int]
        self.sensorId = None  # type: Optional[int]
        self.remoteSensorId = None  # type: Optional[int]
        self.alertDelay = None  # type: Optional[int]
        self.alertLevels = list()  # type: List[int]
        self.description = None  # type: Optional[str]
        self.lastStateUpdated = None  # type: Optional[int]
        self.state = None  # type: Optional[int]
        self.dataType = None  # type: Optional[int]
        self.data = None  # type: Any

    # This function copies all attributes of the given sensor to this object.
    def deepcopy(self, sensor):
        self.nodeId = sensor.nodeId
        self.sensorId = sensor.sensorId
        self.remoteSensorId = sensor.remoteSensorId
        self.alertDelay = sensor.alertDelay
        self.alertLevels = list(sensor.alertLevels)
        self.description = sensor.description
        self.lastStateUpdated = sensor.lastStateUpdated
        self.state = sensor.state
        self.dataType = sensor.dataType
        self.data = sensor.data
        return self

# this class represents a manager client of the alert system
class Manager(LocalObject):

    def __init__(self):
        super().__init__()
        self.nodeId = None  # type: Optional[int]
        self.managerId = None  # type: Optional[int]
        self.description = None  # type: Optional[str]

    # This function copies all attributes of the given manager to this object.
    def deepcopy(self, manager):
        self.nodeId = manager.nodeId
        self.managerId = manager.managerId
        self.description = manager.description
        return self

# this class represents an alert client of the alert system
class Alert(LocalObject):

    def __init__(self):
        super().__init__()
        self.nodeId = None  # type: Optional[int]
        self.alertId = None  # type: Optional[int]
        self.remoteAlertId = None  # type: Optional[int]
        self.alertLevels = list()  # type: List[int]
        self.description = None  # type: Optional[str]

    # This function copies all attributes of the given alert to this object.
    def deepcopy(self, alert):
        self.nodeId = alert.nodeId
        self.alertId = alert.alertId
        self.remoteAlertId = alert.remoteAlertId
        self.alertLevels = list(alert.alertLevels)
        self.description = alert.description
        return self

# this class represents a triggered sensor alert of the alert system
class SensorAlert(LocalObject):

    def __init__(self):
        super().__init__()

        self.sensorId = None  # type: Optional[int]

        # State of the sensor alert ("triggered" = 1; "normal" = 0).
        self.state = None  # type: Optional[int]

        # Description of the sensor that raised this sensor alert.
        self.description = None  # type: Optional[str]

        # Time this sensor alert was received.
        self.timeReceived = None  # type: Optional[int]

        # List of alert levels (Integer) that are triggered
        # by this sensor alert.
        self.alertLevels = list()  # type: List[int]

        # The optional data of the sensor alert (if it has any).
        self.hasOptionalData = None  # type: Optional[bool]
        self.optionalData = None  # type: Dict[str, Any]

        # Does this sensor alert change the state of the sensor?
        self.changeState = None  # type: Optional[bool]

        # Does this sensor alert hold the latest data of the sensor?
        self.hasLatestData = None  # type: Optional[bool]

        # The sensor data type and data that is connected to this sensor alert.
        self.dataType = None  # type: Optional[int]
        self.sensorData = None  # type: Any

    def __str__(self):
        tmp = "Sensor Alert (Description: '%s'; " \
              % self.description \
              + "SensorID: %s; " \
              % str(self.sensorId) if self.sensorId is not None else "None" \
              + "State: %s; " \
              % str(self.state) if self.state is not None else "None" \
              + "Time Received: %s; " \
              % str(self.timeReceived) if self.timeReceived is not None else "None" \
              + "Alert Levels: %s)" \
              % ", ".join(map(str, self.alertLevels))
        return tmp

    # This function copies all attributes of the given sensor alert to this object.
    def deepcopy(self, sensor_alert):
        self.sensorId = sensor_alert.sensorId
        self.state = sensor_alert.state
        self.description = sensor_alert.description
        self.timeReceived = sensor_alert.timeReceived
        self.alertLevels = list(sensor_alert.alertLevels)
        self.hasOptionalData = sensor_alert.hasOptionalData
        self.changeState = sensor_alert.changeState
        self.hasLatestData = sensor_alert.hasLatestData
        self.dataType = sensor_alert.dataType
        self.sensorData = sensor_alert.sensorData

        if type(sensor_alert.optionalData) == dict:
            self.optionalData = copy.deepcopy(sensor_alert.optionalData)

        else:
            self.optionalData = None

        return self

# this class represents an alert level that is configured on the server
class AlertLevel(LocalObject):

    def __init__(self):
        super().__init__()
        self.level = None  # type: Optional[int]
        self.name = None  # type: Optional[str]
        self.triggerAlways = None  # type: Optional[int]
        self.instrumentation_active = None  # type: Optional[bool]
        self.instrumentation_cmd = None  # type: Optional[str]
        self.instrumentation_timeout = None  # type: Optional[int]

    # This function copies all attributes of the given alert level to this object.
    def deepcopy(self, alert_level):
        self.level = alert_level.level
        self.name = alert_level.name
        self.triggerAlways = alert_level.triggerAlways
        self.instrumentation_active = alert_level.instrumentation_active
        if self.instrumentation_active:
            self.instrumentation_cmd = alert_level.instrumentation_cmd
            self.instrumentation_timeout = alert_level.instrumentation_timeout

        else:
            self.instrumentation_cmd = None
            self.instrumentation_timeout = None
        return self
<|endoftext|>


<commit_before>import base
from .. import bar, hook

import gobject

class Clipboard(base._TextBox):
    defaults = [
        ("selection", "CLIPBOARD",
            "the selection to display(CLIPBOARD or PRIMARY)"),
        ("max_width", 10, "size in pixels of task title"),
        ("timeout", 10,
            "Default timeout (seconds) for display text, None to keep forever")
        ]

    def __init__(self, width=bar.CALCULATED, **config):
        base._TextBox.__init__(self, "", width, **config)
        self.add_defaults(Clipboard.defaults)
        self.timeout_id = None

    def _configure(self, qtile, bar):
        base._TextBox._configure(self, qtile, bar)
        self.text = ""
        self.setup_hooks()

    def clear(self, *args):
        self.text = ""
        self.bar.draw()

    def setup_hooks(self):
        def hook_change(name, selection):
            if name != self.selection:
                return
            text = selection["selection"].replace("\n", " ")
            text = text.strip()
            if len(text) > self.max_width:
                text = text[:self.max_width] + "..."
            self.text = text

            if self.timeout_id:
                gobject.source_remove(self.timeout_id)
                self.timeout_id = None

            if self.timeout:
                self.timeout_id = self.timeout_add(self.timeout, self.clear)
            self.bar.draw()

        def hook_notify(name, selection):
            if name != self.selection:
                return

            if self.timeout_id:
                gobject.source_remove(self.timeout_id)
                self.timeout_id = None

            # only clear if don't change don't apply in .5 seconds
            self.timeout_id = self.timeout_add(.5, self.clear)

        hook.subscribe.selection_notify(hook_notify)
        hook.subscribe.selection_change(hook_change)
<commit_msg>add support to blacklist clipboard windows by wm_class<commit_after>import base
from .. import bar, hook

from .. import xcbq
import gobject

class Clipboard(base._TextBox):
    defaults = [
        ("selection", "CLIPBOARD",
            "the selection to display(CLIPBOARD or PRIMARY)"),
        ("max_width", 10, "size in pixels of task title"),
        ("timeout", 10,
            "Default timeout (seconds) for display text, None to keep forever"
         ),
        ("blacklist", ["keepassx"],
            "list with blacklisted wm_class, sadly not every "
            "clipboard window sets them, keepassx does"),
        ("blacklist_text", "***********",
            "text to display when the wm_class is blacklisted"
         )
        ]

    def __init__(self, width=bar.CALCULATED, **config):
        base._TextBox.__init__(self, "", width, **config)
        self.add_defaults(Clipboard.defaults)
        self.timeout_id = None

    def _configure(self, qtile, bar):
        base._TextBox._configure(self, qtile, bar)
        self.text = ""
        self.setup_hooks()

    def clear(self, *args):
        self.text = ""
        self.bar.draw()

    def is_blacklisted(self, owner_id):
        if not self.blacklist:
            return False

        if owner_id in self.qtile.windowMap:
            owner = self.qtile.windowMap[owner_id].window
        else:
            owner = xcbq.Window(self.qtile.conn, owner_id)

        owner_class = owner.get_wm_class()
        if owner_class:
            for wm_class in self.blacklist:
                if wm_class in owner_class:
                    return True

    def setup_hooks(self):
        def hook_change(name, selection):
            if name != self.selection:
                return

            if self.is_blacklisted(selection["owner"]):
                text = self.blacklist_text
            else:
                text = selection["selection"].replace("\n", " ")

                text = text.strip()
                if len(text) > self.max_width:
                    text = text[:self.max_width] + "..."

            self.text = text

            if self.timeout_id:
                gobject.source_remove(self.timeout_id)
                self.timeout_id = None

            if self.timeout:
                self.timeout_id = self.timeout_add(self.timeout, self.clear)
            self.bar.draw()

        def hook_notify(name, selection):
            if name != self.selection:
                return

            if self.timeout_id:
                gobject.source_remove(self.timeout_id)
                self.timeout_id = None

            # only clear if don't change don't apply in .5 seconds
            self.timeout_id = self.timeout_add(.5, self.clear)

        hook.subscribe.selection_notify(hook_notify)
        hook.subscribe.selection_change(hook_change)
<|endoftext|>


<commit_before>from __future__ import division

import numpy as np

import chainer

from chainercv import transforms

def mask_to_segm(mask, bbox, segm_size, index=None):
    """Crop and resize mask.

    This function requires cv2.

    Args:
        mask (~numpy.ndarray): See below.
        bbox (~numpy.ndarray): See below.
        segm_size (int): The size of segm :math:`S`.
        index (~numpy.ndarray): See below. :math:`R = N` when
            :obj:`index` is :obj:`None`.

    Returns:
        ~numpy.ndarray: See below.

    .. csv-table::
        :header: name, shape, dtype, format

        :obj:`mask`, ":math:`(N, H, W)`", :obj:`bool`, --
        :obj:`bbox`, ":math:`(R, 4)`", :obj:`float32`, \
        ":math:`(y_{min}, x_{min}, y_{max}, x_{max})`"
        :obj:`index` (optional), ":math:`(R,)`", :obj:`int32`, --
        :obj:`segms` (output), ":math:`(R, S, S)`", :obj:`float32`, \
        ":math:`[0, 1]`"

    """
    pad = 1

    _, H, W = mask.shape
    bbox = chainer.backends.cuda.to_cpu(bbox)

    # To work around an issue with cv2.resize (it seems to automatically
    # pad with repeated border values), we manually zero-pad the masks by 1
    # pixel prior to resizing back to the original image resolution.
    # This prevents "top hat" artifacts. We therefore need to expand
    # the reference boxes by an appropriate factor.
    padded_segm_size = segm_size + pad * 2
    expand_scale = padded_segm_size / segm_size
    bbox = _expand_bbox(bbox, expand_scale)
    resize_size = padded_segm_size
    bbox = _integerize_bbox(bbox)

    segm = []
    if index is None:
        index = np.arange(len(bbox))
    else:
        index = chainer.backends.cuda.to_cpu(index)

    for i, bb in zip(index, bbox):
        y_min = max(bb[0], 0)
        x_min = max(bb[1], 0)
        y_max = max(min(bb[2], H), 0)
        x_max = max(min(bb[3], W), 0)
        if y_max - y_min == 0 or x_max - x_min == 0:
            segm.append(np.zeros((segm_size, segm_size), dtype=np.float32))
            continue

        bb_height = bb[2] - bb[0]
        bb_width = bb[3] - bb[1]
        cropped_m = np.zeros((bb_height, bb_width), dtype=np.bool)

        y_offset = y_min - bb[0]
        x_offset = x_min - bb[1]
        try:
            cropped_m[y_offset:y_offset + y_max - y_min,
                    x_offset:x_offset + x_max - x_min] =\
                chainer.backends.cuda.to_cpu(mask[i, y_min:y_max, x_min:x_max])
        except Exception as e:
            print(str(type(e)), e)
            print('ymin:', y_min)
            print('ymax:', y_max)
            print('xmin:', x_min)
            print('xmax:', x_max)
            print('y_offset:', y_offset)
            print('x_offset:', x_offset)
            print('bb:', bb)
            raise e

        with chainer.using_config('cv_resize_backend', 'cv2'):
            sgm = transforms.resize(
                cropped_m[None].astype(np.float32),
                (resize_size, resize_size))[0].astype(np.int32)
        segm.append(sgm[pad:-pad, pad:-pad])

    return np.array(segm, dtype=np.float32)

def segm_to_mask(segm, bbox, size):
    """Recover mask from cropped and resized mask.

    This function requires cv2.

    Args:
        segm (~numpy.ndarray): See below.
        bbox (~numpy.ndarray): See below.
        size (tuple): This is a tuple of length 2. Its elements are
            ordered as (height, width).

    Returns:
        ~numpy.ndarray: See below.

    .. csv-table::
        :header: name, shape, dtype, format

        :obj:`segm`, ":math:`(R, S, S)`", :obj:`float32`, --
        :obj:`bbox`, ":math:`(R, 4)`", :obj:`float32`, \
        ":math:`(y_{min}, x_{min}, y_{max}, x_{max})`"
        :obj:`mask` (output), ":math:`(R, H, W)`", :obj:`bool`, --

    """
    pad = 1
    H, W = size
    _, segm_size, _ = segm.shape

    mask = np.zeros((len(bbox), H, W), dtype=np.bool)

    # As commented in mask_to_segm, cv2.resize needs adjust.
    padded_segm_size = segm_size + pad * 2
    expand_scale = padded_segm_size / segm_size
    bbox = _expand_bbox(bbox, expand_scale)
    canvas_mask = np.zeros(
        (padded_segm_size, padded_segm_size), dtype=np.float32)
    bbox = _integerize_bbox(bbox)

    for i, (bb, sgm) in enumerate(zip(bbox, segm)):
        bb_height = bb[2] - bb[0]
        bb_width = bb[3] - bb[1]
        if bb_height == 0 or bb_width == 0:
            continue

        canvas_mask[pad:-pad, pad:-pad] = sgm

        with chainer.using_config('cv_resize_backend', 'cv2'):
            crop_mask = transforms.resize(
                canvas_mask[None], (bb_height, bb_width))[0]
        crop_mask = crop_mask > 0.5

        y_min = max(bb[0], 0)
        x_min = max(bb[1], 0)
        y_max = max(min(bb[2], H), 0)
        x_max = max(min(bb[3], W), 0)
        y_offset = y_min - bb[0]
        x_offset = x_min - bb[1]
        mask[i, y_min:y_max, x_min:x_max] = crop_mask[
            y_offset:y_offset + y_max - y_min,
            x_offset:x_offset + x_max - x_min]
    return mask

def _integerize_bbox(bbox):
    return np.round(bbox).astype(np.int32)

def _expand_bbox(bbox, scale):
    """Expand an array of boxes by a given scale."""
    xp = chainer.backends.cuda.get_array_module(bbox)

    h_half = (bbox[:, 2] - bbox[:, 0]) * .5
    w_half = (bbox[:, 3] - bbox[:, 1]) * .5
    y_c = (bbox[:, 2] + bbox[:, 0]) * .5
    x_c = (bbox[:, 3] + bbox[:, 1]) * .5

    h_half *= scale
    w_half *= scale

    expanded_bbox = xp.zeros(bbox.shape)
    expanded_bbox[:, 0] = y_c - h_half
    expanded_bbox[:, 1] = x_c - w_half
    expanded_bbox[:, 2] = y_c + h_half
    expanded_bbox[:, 3] = x_c + w_half

    return expanded_bbox
<commit_msg>Show details of variables<commit_after>from __future__ import division

import numpy as np

import chainer

from chainercv import transforms

def mask_to_segm(mask, bbox, segm_size, index=None):
    """Crop and resize mask.

    This function requires cv2.

    Args:
        mask (~numpy.ndarray): See below.
        bbox (~numpy.ndarray): See below.
        segm_size (int): The size of segm :math:`S`.
        index (~numpy.ndarray): See below. :math:`R = N` when
            :obj:`index` is :obj:`None`.

    Returns:
        ~numpy.ndarray: See below.

    .. csv-table::
        :header: name, shape, dtype, format

        :obj:`mask`, ":math:`(N, H, W)`", :obj:`bool`, --
        :obj:`bbox`, ":math:`(R, 4)`", :obj:`float32`, \
        ":math:`(y_{min}, x_{min}, y_{max}, x_{max})`"
        :obj:`index` (optional), ":math:`(R,)`", :obj:`int32`, --
        :obj:`segms` (output), ":math:`(R, S, S)`", :obj:`float32`, \
        ":math:`[0, 1]`"

    """
    pad = 1

    _, H, W = mask.shape
    bbox = chainer.backends.cuda.to_cpu(bbox)

    # To work around an issue with cv2.resize (it seems to automatically
    # pad with repeated border values), we manually zero-pad the masks by 1
    # pixel prior to resizing back to the original image resolution.
    # This prevents "top hat" artifacts. We therefore need to expand
    # the reference boxes by an appropriate factor.
    padded_segm_size = segm_size + pad * 2
    expand_scale = padded_segm_size / segm_size
    bbox = _expand_bbox(bbox, expand_scale)
    resize_size = padded_segm_size
    bbox = _integerize_bbox(bbox)

    segm = []
    if index is None:
        index = np.arange(len(bbox))
    else:
        index = chainer.backends.cuda.to_cpu(index)

    for i, bb in zip(index, bbox):
        y_min = max(bb[0], 0)
        x_min = max(bb[1], 0)
        y_max = max(min(bb[2], H), 0)
        x_max = max(min(bb[3], W), 0)
        if y_max - y_min == 0 or x_max - x_min == 0:
            segm.append(np.zeros((segm_size, segm_size), dtype=np.float32))
            continue

        bb_height = bb[2] - bb[0]
        bb_width = bb[3] - bb[1]
        cropped_m = np.zeros((bb_height, bb_width), dtype=np.bool)

        y_offset = y_min - bb[0]
        x_offset = x_min - bb[1]
        try:
            cropped_m[y_offset:y_offset + y_max - y_min,
                    x_offset:x_offset + x_max - x_min] =\
                chainer.backends.cuda.to_cpu(mask[i, y_min:y_max, x_min:x_max])
        except Exception as e:
            print(str(type(e)), e)
            print('ymin: {}, ymax: {}, xmin: {}, xmax: {}, y_offset: {}, x_offset: {}, bb: {}, mask: {}'.format(
                y_min, y_max, x_min, x_max, y_offset, x_offset, bb, mask.shape))
            raise e

        with chainer.using_config('cv_resize_backend', 'cv2'):
            sgm = transforms.resize(
                cropped_m[None].astype(np.float32),
                (resize_size, resize_size))[0].astype(np.int32)
        segm.append(sgm[pad:-pad, pad:-pad])

    return np.array(segm, dtype=np.float32)

def segm_to_mask(segm, bbox, size):
    """Recover mask from cropped and resized mask.

    This function requires cv2.

    Args:
        segm (~numpy.ndarray): See below.
        bbox (~numpy.ndarray): See below.
        size (tuple): This is a tuple of length 2. Its elements are
            ordered as (height, width).

    Returns:
        ~numpy.ndarray: See below.

    .. csv-table::
        :header: name, shape, dtype, format

        :obj:`segm`, ":math:`(R, S, S)`", :obj:`float32`, --
        :obj:`bbox`, ":math:`(R, 4)`", :obj:`float32`, \
        ":math:`(y_{min}, x_{min}, y_{max}, x_{max})`"
        :obj:`mask` (output), ":math:`(R, H, W)`", :obj:`bool`, --

    """
    pad = 1
    H, W = size
    _, segm_size, _ = segm.shape

    mask = np.zeros((len(bbox), H, W), dtype=np.bool)

    # As commented in mask_to_segm, cv2.resize needs adjust.
    padded_segm_size = segm_size + pad * 2
    expand_scale = padded_segm_size / segm_size
    bbox = _expand_bbox(bbox, expand_scale)
    canvas_mask = np.zeros(
        (padded_segm_size, padded_segm_size), dtype=np.float32)
    bbox = _integerize_bbox(bbox)

    for i, (bb, sgm) in enumerate(zip(bbox, segm)):
        bb_height = bb[2] - bb[0]
        bb_width = bb[3] - bb[1]
        if bb_height == 0 or bb_width == 0:
            continue

        canvas_mask[pad:-pad, pad:-pad] = sgm

        with chainer.using_config('cv_resize_backend', 'cv2'):
            crop_mask = transforms.resize(
                canvas_mask[None], (bb_height, bb_width))[0]
        crop_mask = crop_mask > 0.5

        y_min = max(bb[0], 0)
        x_min = max(bb[1], 0)
        y_max = max(min(bb[2], H), 0)
        x_max = max(min(bb[3], W), 0)
        y_offset = y_min - bb[0]
        x_offset = x_min - bb[1]
        mask[i, y_min:y_max, x_min:x_max] = crop_mask[
            y_offset:y_offset + y_max - y_min,
            x_offset:x_offset + x_max - x_min]
    return mask

def _integerize_bbox(bbox):
    return np.round(bbox).astype(np.int32)

def _expand_bbox(bbox, scale):
    """Expand an array of boxes by a given scale."""
    xp = chainer.backends.cuda.get_array_module(bbox)

    h_half = (bbox[:, 2] - bbox[:, 0]) * .5
    w_half = (bbox[:, 3] - bbox[:, 1]) * .5
    y_c = (bbox[:, 2] + bbox[:, 0]) * .5
    x_c = (bbox[:, 3] + bbox[:, 1]) * .5

    h_half *= scale
    w_half *= scale

    expanded_bbox = xp.zeros(bbox.shape)
    expanded_bbox[:, 0] = y_c - h_half
    expanded_bbox[:, 1] = x_c - w_half
    expanded_bbox[:, 2] = y_c + h_half
    expanded_bbox[:, 3] = x_c + w_half

    return expanded_bbox
<|endoftext|>


<commit_before>"""The plug in to run on batlab.

This module is available as an polyphemus plugin by the name ``polyphemus.swchook``.

SWC Hook API
============
"""
from __future__ import print_function
import os
import shutil
import sys
import subprocess
from warnings import warn

try:
    import simplejson as json
except ImportError:
    import json

import github3

from .utils import RunControl, NotSpecified, PersistentCache
from .plugins import Plugin
from .event import Event, runfor
from .githubbase import set_pull_request_status

if sys.version_info[0] >= 3:
    basestring = str

clone_template = """git clone {url} {dir}"""

checkout_template = """git checkout {commit}"""

rem_add_template = """git remote add {branch} {url}"""

fetch_template = """git fetch {branch}"""

merge_template = """git merge {branch}/{commit}"""

html_diff_template = """htmldiff {file1} {file2}"""

build_html = """make clean; make cache; make check;"""

def clone_repo(url, dir):
    subprocess.check_call(
        clone_template.format(url=url, dir=dir).split(),
        cwd=os.getcwd(), shell=(os.name == 'nt'))

def checkout_commit(commit, cwd=None):
    if cwd is None:
        cwd = os.getcwd()
    subprocess.check_call(
        checkout_template.format(commit=commit).split(),
        cwd=cwd, shell=(os.name == 'nt'))

def add_fetch_remote(rem_branch, rem_url, cwd=None):
    if cwd is None:
        cwd = os.getcwd()
    subprocess.check_call(
        rem_add_template.format(branch=rem_branch, url=rem_url).split(),
        cwd=cwd, shell=(os.name == 'nt'))
    subprocess.check_call(
        fetch_template.format(branch=rem_branch).split(),
        cwd=cwd, shell=(os.name == 'nt'))

def merge_commit(merge_branch, merge_ref, cwd=None):
    subprocess.check_call(
        merge_template.format(branch=merge_branch,
                              commit=merge_ref).split(),
        cwd=cwd, shell=(os.name == 'nt'))

class PolyphemusPlugin(Plugin):
    """This class provides functionality for comparing SWC website PRs.
    """

    requires = ('polyphemus.swcbase',)

    def __init__(self):
        self._files = []
        self._home_dir = os.path.abspath(os.getcwd())

    def _build_base_html(self, base):
        base_repo = github3.repository(*base.repo)

        if os.path.exists(self._base_dir):
            shutil.rmtree(self._base_dir)

        self._updater.update(
            status='pending', description="Getting base repository.")
        clone_repo(base_repo.clone_url, self._base_dir)
        checkout_commit(base.ref, cwd=self._base_dir)

        self._updater.update(
            status='pending', description="Building base website.")
        subprocess.check_call(build_html, cwd=self._base_dir, shell=True)

    def _build_head_html(self, base, head):
        head_repo = github3.repository(*head.repo)
        base_repo = github3.repository(*base.repo)

        if os.path.exists(self._head_dir):
            shutil.rmtree(self._head_dir)

        self._updater.update(
            status='pending', description="Getting head repository.")
        clone_repo(head_repo.clone_url, self._head_dir)
        add_fetch_remote("upstream", base_repo.clone_url,
                         cwd=self._head_dir)
        checkout_commit(base.ref, cwd=self._head_dir)
        merge_commit("origin", head.ref, cwd=self._head_dir)

        self._updater.update(
            status='pending', description="Building head website.")
        subprocess.check_call(build_html, shell=True, cwd=self._head_dir)

    def _generate_diffs(self):
        if os.path.exists(self._diff_dir):
            shutil.rmtree(self._diff_dir)

        self._updater.update(
            status='pending',
            description="Creating head and base website diffs.")

        for f in self._files:
            fpath, fname = os.path.split(f)
            d = os.path.join(self._diff_dir, fpath)
            os.makedirs(d)

            head = os.path.join(self._head_dir, f)
            base = os.path.join(self._base_dir, f)
            diff = os.path.join(self._diff_dir, f)

            try:
                diff_txt = subprocess.check_output(
                    html_diff_template.format(file1=base,
                                              file2=head).split(),
                    shell=(os.name == 'nt'))
            except OSError:
                msg = "Error, htmldiff not installed on the server."
                warn(msg, RuntimeWarning)
                self._updater['description'] = msg
                return

            with open(diff, 'w') as f:
                f.write(diff_txt)

    def _dump_state(self):
        with open('swc_state.json', 'w') as outfile:
            json.dumps({'base': self._base_dir,
                        'head': self._head_dir,
                        'diff': self._diff_dir,
                        'files': self._files},
                       outfile, indent=4, separators=(',', ': '))

    def execute(self, rc):
        event_name = rc.event.name
        pr = rc.event.data  # pull request object

        rc.event = Event(name='swc-status',
                         data={'status': 'error',
                               'number': pr.number,
                               'description': ''})
        self._updater = rc.event.data

        if not pr.mergeable:
            msg = "Error, PR #{0} is not mergeable.".format(pr.number)
            warn(msg, RuntimeError)
            rc.event.data['status'] = 'failure'
            self._updater['description'] = msg
            return

        self._files = [os.path.join(*f.filename.split("/"))
                       for f in pr.iter_files()]

        self._base_dir = os.path.join(self._home_dir,
                                      str(pr.number), "base")
        self._head_dir = os.path.join(self._home_dir,
                                      str(pr.number), "head")
        self._diff_dir = os.path.join(self._home_dir,
                                      str(pr.number), "diff")

        self._build_head_html(pr.base, pr.head)
        self._build_base_html(pr.base)
        self._generate_diffs()
        self._dump_state()
<commit_msg>double checking fpath split<commit_after>"""The plug in to run on batlab.

This module is available as an polyphemus plugin by the name ``polyphemus.swchook``.

SWC Hook API
============
"""
from __future__ import print_function
import os
import shutil
import sys
import subprocess
from warnings import warn

try:
    import simplejson as json
except ImportError:
    import json

import github3

from .utils import RunControl, NotSpecified, PersistentCache
from .plugins import Plugin
from .event import Event, runfor
from .githubbase import set_pull_request_status

if sys.version_info[0] >= 3:
    basestring = str

clone_template = """git clone {url} {dir}"""

checkout_template = """git checkout {commit}"""

rem_add_template = """git remote add {branch} {url}"""

fetch_template = """git fetch {branch}"""

merge_template = """git merge {branch}/{commit}"""

html_diff_template = """htmldiff {file1} {file2}"""

build_html = """make clean; make cache; make check;"""

def clone_repo(url, dir):
    subprocess.check_call(
        clone_template.format(url=url, dir=dir).split(),
        cwd=os.getcwd(), shell=(os.name == 'nt'))

def checkout_commit(commit, cwd=None):
    if cwd is None:
        cwd = os.getcwd()
    subprocess.check_call(
        checkout_template.format(commit=commit).split(),
        cwd=cwd, shell=(os.name == 'nt'))

def add_fetch_remote(rem_branch, rem_url, cwd=None):
    if cwd is None:
        cwd = os.getcwd()
    subprocess.check_call(
        rem_add_template.format(branch=rem_branch, url=rem_url).split(),
        cwd=cwd, shell=(os.name == 'nt'))
    subprocess.check_call(
        fetch_template.format(branch=rem_branch).split(),
        cwd=cwd, shell=(os.name == 'nt'))

def merge_commit(merge_branch, merge_ref, cwd=None):
    subprocess.check_call(
        merge_template.format(branch=merge_branch,
                              commit=merge_ref).split(),
        cwd=cwd, shell=(os.name == 'nt'))

class PolyphemusPlugin(Plugin):
    """This class provides functionality for comparing SWC website PRs.
    """

    requires = ('polyphemus.swcbase',)

    def __init__(self):
        self._files = []
        self._home_dir = os.path.abspath(os.getcwd())

    def _build_base_html(self, base):
        base_repo = github3.repository(*base.repo)

        if os.path.exists(self._base_dir):
            shutil.rmtree(self._base_dir)

        self._updater.update(
            status='pending', description="Getting base repository.")
        clone_repo(base_repo.clone_url, self._base_dir)
        checkout_commit(base.ref, cwd=self._base_dir)

        self._updater.update(
            status='pending', description="Building base website.")
        subprocess.check_call(build_html, cwd=self._base_dir, shell=True)

    def _build_head_html(self, base, head):
        head_repo = github3.repository(*head.repo)
        base_repo = github3.repository(*base.repo)

        if os.path.exists(self._head_dir):
            shutil.rmtree(self._head_dir)

        self._updater.update(
            status='pending', description="Getting head repository.")
        clone_repo(head_repo.clone_url, self._head_dir)
        add_fetch_remote("upstream", base_repo.clone_url,
                         cwd=self._head_dir)
        checkout_commit(base.ref, cwd=self._head_dir)
        merge_commit("origin", head.ref, cwd=self._head_dir)

        self._updater.update(
            status='pending', description="Building head website.")
        subprocess.check_call(build_html, shell=True, cwd=self._head_dir)

    def _generate_diffs(self):
        if os.path.exists(self._diff_dir):
            shutil.rmtree(self._diff_dir)

        self._updater.update(
            status='pending',
            description="Creating head and base website diffs.")

        for f in self._files:
            fpath, fname = os.path.split(f)
            print(fpath, fname)
            d = os.path.join(self._diff_dir, fpath)
            os.makedirs(d)

            head = os.path.join(self._head_dir, f)
            base = os.path.join(self._base_dir, f)
            diff = os.path.join(self._diff_dir, f)

            try:
                diff_txt = subprocess.check_output(
                    html_diff_template.format(file1=base,
                                              file2=head).split(),
                    shell=(os.name == 'nt'))
            except OSError:
                msg = "Error, htmldiff not installed on the server."
                warn(msg, RuntimeWarning)
                self._updater['description'] = msg
                return

            with open(diff, 'w') as f:
                f.write(diff_txt)

    def _dump_state(self):
        with open('swc_state.json', 'w') as outfile:
            json.dumps({'base': self._base_dir,
                        'head': self._head_dir,
                        'diff': self._diff_dir,
                        'files': self._files},
                       outfile, indent=4, separators=(',', ': '))

    def execute(self, rc):
        event_name = rc.event.name
        pr = rc.event.data  # pull request object

        rc.event = Event(name='swc-status',
                         data={'status': 'error',
                               'number': pr.number,
                               'description': ''})
        self._updater = rc.event.data

        if not pr.mergeable:
            msg = "Error, PR #{0} is not mergeable.".format(pr.number)
            warn(msg, RuntimeError)
            rc.event.data['status'] = 'failure'
            self._updater['description'] = msg
            return

        self._files = [os.path.join(*f.filename.split("/"))
                       for f in pr.iter_files()]

        self._base_dir = os.path.join(self._home_dir,
                                      str(pr.number), "base")
        self._head_dir = os.path.join(self._home_dir,
                                      str(pr.number), "head")
        self._diff_dir = os.path.join(self._home_dir,
                                      str(pr.number), "diff")

        self._build_head_html(pr.base, pr.head)
        self._build_base_html(pr.base)
        self._generate_diffs()
        self._dump_state()
<|endoftext|>


<commit_before>#    Copyright 2017 SAS Project Authors. All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

import json
import logging
import math
import os
import sas
import sas_testcase
from reference_models.propagation import wf_itm
from reference_models.propagation import wf_hybrid
from reference_models.antenna import antenna
from reference_models.ppa import ppa
from reference_models.geo import drive

from util import winnforum_testcase, configurable_testcase, writeConfig, loadConfig
from reference_models.geo import utils as geoutils

def computePropagationAntennaModel(request):
    reliability_level = request['reliabilityLevel']
    if reliability_level not in [-1, 0.05, 0.95]:
        raise ValueError('reliability_level not in [-1, 0.05, 0.95]')

    tx = request['cbsd']
    if ('fss' in request) and ('ppa' in request):
        raise ValueError('fss and ppa in request')
    elif 'ppa' in request:
        rx ={}
        rx['height'] = 1.5
        isfss = False
        coordinates = []
        ppa = request['ppa']

        arcsec = 1
        ppa_points = geoutils.GridPolygon(ppa['geometry'], arcsec)
        if len(ppa_points) == 1:
            rx['longitude']= ppa_points[0][0]
            rx['latitude'] = ppa_points[0][1]
        elif len(ppa_points) == 0:
            raise ValueError('ppa boundary contains no protection point')
        else:
            raise ValueError('ppa boundary contains more than a single protection point')

        region_val = drive.nlcd_driver.RegionNlcdVote([[rx['latitude'], rx['longitude']]])

    elif 'fss' in request:
        isfss = True
        rx = request['fss']
    else:
        raise ValueError('Neither fss nor ppa in request')

    # ITM pathloss (if receiver type is FSS) or the hybrid model pathloss (if receiver type is PPA) and corresponding antenna gains.
    # The test specification notes that the SAS UUT shall use default values for w1 and w2 in the ITM model.
    result = {}
    if isfss:
        path_loss = wf_itm.CalcItmPropagationLoss(
            tx['latitude'], tx['longitude'], tx['height'],
            rx['latitude'], rx['longitude'], rx['height'],
            cbsd_indoor= tx['indoorDeployment'],
            reliability=reliability_level,
            freq_mhz=3625.,
            is_height_cbsd_amsl=(tx['heightType'] == 'AMSL'))

        result['pathlossDb'] = path_loss.db_loss
        gain_tx_rx = antenna.GetStandardAntennaGains(
            path_loss.incidence_angles.hor_cbsd, ant_azimuth=tx['antennaAzimuth'],
            ant_beamwidth=tx['antennaBeamwidth'], ant_gain=tx['antennaGain'])
        result['txAntennaGainDbi'] = gain_tx_rx
        if 'rxAntennaGainRequired' in rx:
            hor_dirs = path_loss.incidence_angles.hor_rx
            ver_dirs = path_loss.incidence_angles.ver_rx
            gain_rx_tx = antenna.GetFssAntennaGains(
                hor_dirs, ver_dirs, rx['antennaAzimuth'],
                rx['antennaElevation'], rx['antennaGain'])
            result['rxAntennaGainDbi'] = gain_rx_tx
    else:

        path_loss = wf_hybrid.CalcHybridPropagationLoss(
            tx['latitude'], tx['longitude'], tx['height'],
            rx['latitude'], rx['longitude'], rx['height'],
            cbsd_indoor= tx['indoorDeployment'],
            reliability=-1, freq_mhz=3625., region=region_val,
            is_height_cbsd_amsl=(tx['heightType'] == 'AMSL'))
        result['pathlossDb'] = path_loss.db_loss
        gain_tx_rx = antenna.GetStandardAntennaGains(
            path_loss.incidence_angles.hor_cbsd, ant_azimuth=tx['antennaAzimuth'],
            ant_beamwidth=tx['antennaBeamwidth'], ant_gain=tx['antennaGain'])
        result['txAntennaGainDbi'] = gain_tx_rx

    return result

def cbsddata(device):
    installationParam = device['installationParam']
    if 'antennaAzimuth' not in installationParam:
        installationParam['antennaAzimuth'] = None
    if 'antennaBeamwidth' not in installationParam:
        installationParam['antennaBeamwidth'] = None
    if 'antennaGain' not in installationParam:
        installationParam['antennaGain'] = 0

    cbsd = {'latitude': installationParam['latitude'],
            'longitude': installationParam['longitude'],
            'height': installationParam['height'],
            'heightType': installationParam['heightType'],
            'indoorDeployment': installationParam['indoorDeployment'],
            'antennaAzimuth': installationParam['antennaAzimuth'],
            'antennaGain': installationParam['antennaGain'],
            'antennaBeamwidth': installationParam['antennaBeamwidth']}
    return cbsd

def fssdata(fss_record, rx_antenna_gain_required=None):
    deploymentParam = fss_record['deploymentParam'][0]
    installationParam = deploymentParam['installationParam']
    if 'antennaAzimuth' not in installationParam:
        installationParam['antennaAzimuth'] = None

    fss = {'latitude': installationParam['latitude'],
           'longitude': installationParam['longitude'],
           'height': installationParam['height'],
           'antennaAzimuth': installationParam['antennaAzimuth'],
           'antennaGain': installationParam['antennaGain'],
           'antennaElevation': -installationParam['antennaDowntilt']}
    if rx_antenna_gain_required is not None:
        fss['rxAntennaGainRequired'] = rx_antenna_gain_required
    else:
        fss['rxAntennaGainRequired'] = False
    return fss

class PropAndAntennaModelTestcase(sas_testcase.SasTestCase):

  def setUp(self):
    self._sas, self._sas_admin = sas.GetTestingSas()
    self._sas_admin.Reset()

  def tearDown(self):
      pass

  def generate_FT_S_PAT_default_config(self, filename):
    """Generates the WinnForum configuration for PAT.1."""

    # Load Devices
    device_a = json.load(
    open(os.path.join('testcases', 'testdata', 'device_a.json')))

    # load FSS
    fss_data = json.load(
      open(os.path.join('testcases', 'testdata', 'fss_record_0.json')))
    fss_record_0 = fss_data['record']
    fss_record_0['rxAntennaGainRequired'] = True
    reliability_level = -1
    config = []
    config.append({'reliabilityLevel': reliability_level,
                   'cbsd': cbsddata(device_a),
                   'fss': fssdata(fss_record_0, True)})

    # Load PPA
    ppa_record = json.load(
        open(os.path.join('testcases', 'testdata', 'ppa_record_3.json')))

    reliability_level = -1
    config.append({'reliabilityLevel': reliability_level,
                   'cbsd': cbsddata(device_a),
                   'ppa': ppa_record['zone']['features'][0]})

    writeConfig(filename, config)

  @configurable_testcase(generate_FT_S_PAT_default_config)
  def test_WINNF_FT_S_PAT_1(self, config_filename):
    """Query with CBSD and FSS/PPA

    If (rxAntennaGainRequired = True)
    The response should have the pathlossDb, txAntennaGainDbi and rxAntennaGainDbi

    If (rxAntennaGainRequired = False or omitted)
    The response should have the pathlossDb, txAntennaGainDbi
    """
    config = loadConfig(config_filename)
    num_tests = len(config)
    test_pass_threshold = 0.999 #percentage of passed test expected
    num_passed_tests = 0
    num_tests = len(config)
    max_fail_num = int ((1-test_pass_threshold) * num_tests)
    num_failed_tests = 0
    num_invalid_tests = 0

    for test_num, request in enumerate(config):
      logging.info('Running test number %d: %s', test_num, str(request))
      try:
        ref_response = computePropagationAntennaModel(request)
        logging.info('Reference response: %s', str(ref_response))
      except ValueError as e:
        logging.debug('Test # %d, Exception: %s', test_num, e)
        logging.debug('Invalid configuration: %s', request)
        num_invalid_tests += 1
        num_tests -= 1
        max_fail_num = math.floor((1-test_pass_threshold) * num_tests)
        # Do not send the request to the SAS if the reference prop model flagged it as an invalid config.
        continue

      # Send the request to the SAS.
      sas_response = self._sas_admin.QueryPropagationAndAntennaModel(request)
      logging.info('SAS response: %s', str(sas_response))

      # Check response.
      this_test_passed = False
      if 'pathlossDb' in sas_response and 'txAntennaGainDbi' in sas_response:
        this_test_passed = ((sas_response['pathlossDb'] < ref_response['pathlossDb'] + 1) and
                            (sas_response['txAntennaGainDbi'] >= (ref_response['txAntennaGainDbi'] - .2)))

        if 'fss' in request and request['fss']['rxAntennaGainRequired']:
          if 'rxAntennaGainDbi' in sas_response:
            this_test_passed = (this_test_passed and
                                (sas_response['rxAntennaGainDbi'] >= (ref_response['rxAntennaGainDbi'] - .2)))
          else:
            this_test_passed = False

      logging.info('This test passed? %s', str(this_test_passed))

      if this_test_passed:
        num_passed_tests += 1
      else:
        num_failed_tests += 1
      if num_failed_tests > max_fail_num: #test fails if number of failed tests greater than allowed
        self.fail("Just failed the maximum number of tests (%d), quitting early." % num_failed_tests)

    # Outside the 'for' loop.
    logging.info('Passed %d out of %d tests. Need %2.6f percent pass rate.',
                 num_passed_tests, num_tests, test_pass_threshold * 100)
    self.assertTrue(num_passed_tests >= num_tests * test_pass_threshold)

<commit_msg>Introduce a flag to turn on/off early-exit in PAT<commit_after>#    Copyright 2017 SAS Project Authors. All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

import json
import logging
import math
import os
import sas
import sas_testcase
from reference_models.propagation import wf_itm
from reference_models.propagation import wf_hybrid
from reference_models.antenna import antenna
from reference_models.ppa import ppa
from reference_models.geo import drive

from util import winnforum_testcase, configurable_testcase, writeConfig, loadConfig
from reference_models.geo import utils as geoutils

# If enabled, the test harness will stop as soon as the failure threshold is reached.
# If disabled, the test harness will execute all subtests and only PASS/FAIL at the end.
EARLY_EXIT_ENABLED = False

def computePropagationAntennaModel(request):
    reliability_level = request['reliabilityLevel']
    if reliability_level not in [-1, 0.05, 0.95]:
        raise ValueError('reliability_level not in [-1, 0.05, 0.95]')

    tx = request['cbsd']
    if ('fss' in request) and ('ppa' in request):
        raise ValueError('fss and ppa in request')
    elif 'ppa' in request:
        rx ={}
        rx['height'] = 1.5
        isfss = False
        coordinates = []
        ppa = request['ppa']

        arcsec = 1
        ppa_points = geoutils.GridPolygon(ppa['geometry'], arcsec)
        if len(ppa_points) == 1:
            rx['longitude']= ppa_points[0][0]
            rx['latitude'] = ppa_points[0][1]
        elif len(ppa_points) == 0:
            raise ValueError('ppa boundary contains no protection point')
        else:
            raise ValueError('ppa boundary contains more than a single protection point')

        region_val = drive.nlcd_driver.RegionNlcdVote([[rx['latitude'], rx['longitude']]])

    elif 'fss' in request:
        isfss = True
        rx = request['fss']
    else:
        raise ValueError('Neither fss nor ppa in request')

    # ITM pathloss (if receiver type is FSS) or the hybrid model pathloss (if receiver type is PPA) and corresponding antenna gains.
    # The test specification notes that the SAS UUT shall use default values for w1 and w2 in the ITM model.
    result = {}
    if isfss:
        path_loss = wf_itm.CalcItmPropagationLoss(
            tx['latitude'], tx['longitude'], tx['height'],
            rx['latitude'], rx['longitude'], rx['height'],
            cbsd_indoor= tx['indoorDeployment'],
            reliability=reliability_level,
            freq_mhz=3625.,
            is_height_cbsd_amsl=(tx['heightType'] == 'AMSL'))

        result['pathlossDb'] = path_loss.db_loss
        gain_tx_rx = antenna.GetStandardAntennaGains(
            path_loss.incidence_angles.hor_cbsd, ant_azimuth=tx['antennaAzimuth'],
            ant_beamwidth=tx['antennaBeamwidth'], ant_gain=tx['antennaGain'])
        result['txAntennaGainDbi'] = gain_tx_rx
        if 'rxAntennaGainRequired' in rx:
            hor_dirs = path_loss.incidence_angles.hor_rx
            ver_dirs = path_loss.incidence_angles.ver_rx
            gain_rx_tx = antenna.GetFssAntennaGains(
                hor_dirs, ver_dirs, rx['antennaAzimuth'],
                rx['antennaElevation'], rx['antennaGain'])
            result['rxAntennaGainDbi'] = gain_rx_tx
    else:

        path_loss = wf_hybrid.CalcHybridPropagationLoss(
            tx['latitude'], tx['longitude'], tx['height'],
            rx['latitude'], rx['longitude'], rx['height'],
            cbsd_indoor= tx['indoorDeployment'],
            reliability=-1, freq_mhz=3625., region=region_val,
            is_height_cbsd_amsl=(tx['heightType'] == 'AMSL'))
        result['pathlossDb'] = path_loss.db_loss
        gain_tx_rx = antenna.GetStandardAntennaGains(
            path_loss.incidence_angles.hor_cbsd, ant_azimuth=tx['antennaAzimuth'],
            ant_beamwidth=tx['antennaBeamwidth'], ant_gain=tx['antennaGain'])
        result['txAntennaGainDbi'] = gain_tx_rx

    return result

def cbsddata(device):
    installationParam = device['installationParam']
    if 'antennaAzimuth' not in installationParam:
        installationParam['antennaAzimuth'] = None
    if 'antennaBeamwidth' not in installationParam:
        installationParam['antennaBeamwidth'] = None
    if 'antennaGain' not in installationParam:
        installationParam['antennaGain'] = 0

    cbsd = {'latitude': installationParam['latitude'],
            'longitude': installationParam['longitude'],
            'height': installationParam['height'],
            'heightType': installationParam['heightType'],
            'indoorDeployment': installationParam['indoorDeployment'],
            'antennaAzimuth': installationParam['antennaAzimuth'],
            'antennaGain': installationParam['antennaGain'],
            'antennaBeamwidth': installationParam['antennaBeamwidth']}
    return cbsd

def fssdata(fss_record, rx_antenna_gain_required=None):
    deploymentParam = fss_record['deploymentParam'][0]
    installationParam = deploymentParam['installationParam']
    if 'antennaAzimuth' not in installationParam:
        installationParam['antennaAzimuth'] = None

    fss = {'latitude': installationParam['latitude'],
           'longitude': installationParam['longitude'],
           'height': installationParam['height'],
           'antennaAzimuth': installationParam['antennaAzimuth'],
           'antennaGain': installationParam['antennaGain'],
           'antennaElevation': -installationParam['antennaDowntilt']}
    if rx_antenna_gain_required is not None:
        fss['rxAntennaGainRequired'] = rx_antenna_gain_required
    else:
        fss['rxAntennaGainRequired'] = False
    return fss

class PropAndAntennaModelTestcase(sas_testcase.SasTestCase):

  def setUp(self):
    self._sas, self._sas_admin = sas.GetTestingSas()
    self._sas_admin.Reset()

  def tearDown(self):
      pass

  def generate_FT_S_PAT_default_config(self, filename):
    """Generates the WinnForum configuration for PAT.1."""

    # Load Devices
    device_a = json.load(
    open(os.path.join('testcases', 'testdata', 'device_a.json')))

    # load FSS
    fss_data = json.load(
      open(os.path.join('testcases', 'testdata', 'fss_record_0.json')))
    fss_record_0 = fss_data['record']
    fss_record_0['rxAntennaGainRequired'] = True
    reliability_level = -1
    config = []
    config.append({'reliabilityLevel': reliability_level,
                   'cbsd': cbsddata(device_a),
                   'fss': fssdata(fss_record_0, True)})

    # Load PPA
    ppa_record = json.load(
        open(os.path.join('testcases', 'testdata', 'ppa_record_3.json')))

    reliability_level = -1
    config.append({'reliabilityLevel': reliability_level,
                   'cbsd': cbsddata(device_a),
                   'ppa': ppa_record['zone']['features'][0]})

    writeConfig(filename, config)

  @configurable_testcase(generate_FT_S_PAT_default_config)
  def test_WINNF_FT_S_PAT_1(self, config_filename):
    """Query with CBSD and FSS/PPA

    If (rxAntennaGainRequired = True)
    The response should have the pathlossDb, txAntennaGainDbi and rxAntennaGainDbi

    If (rxAntennaGainRequired = False or omitted)
    The response should have the pathlossDb, txAntennaGainDbi
    """
    config = loadConfig(config_filename)
    num_tests = len(config)
    test_pass_threshold = 0.999 #percentage of passed test expected
    num_passed_tests = 0
    num_tests = len(config)
    max_fail_num = int ((1-test_pass_threshold) * num_tests)
    num_failed_tests = 0
    num_invalid_tests = 0
    already_failed = False

    for test_num, request in enumerate(config):
      logging.info('Running test number %d: %s', test_num, str(request))
      try:
        ref_response = computePropagationAntennaModel(request)
        logging.info('Reference response: %s', str(ref_response))
      except ValueError as e:
        logging.debug('Test # %d, Exception: %s', test_num, e)
        logging.debug('Invalid configuration: %s', request)
        num_invalid_tests += 1
        num_tests -= 1
        max_fail_num = math.floor((1-test_pass_threshold) * num_tests)
        # Do not send the request to the SAS if the reference prop model flagged it as an invalid config.
        continue

      # Send the request to the SAS.
      sas_response = self._sas_admin.QueryPropagationAndAntennaModel(request)
      logging.info('SAS response: %s', str(sas_response))

      # Check response.
      this_test_passed = False
      if 'pathlossDb' in sas_response and 'txAntennaGainDbi' in sas_response:
        this_test_passed = ((sas_response['pathlossDb'] < ref_response['pathlossDb'] + 1) and
                            (sas_response['txAntennaGainDbi'] >= (ref_response['txAntennaGainDbi'] - .2)))

        if 'fss' in request and request['fss']['rxAntennaGainRequired']:
          if 'rxAntennaGainDbi' in sas_response:
            this_test_passed = (this_test_passed and
                                (sas_response['rxAntennaGainDbi'] >= (ref_response['rxAntennaGainDbi'] - .2)))
          else:
            this_test_passed = False

      logging.info('This test passed? %s', str(this_test_passed))

      if this_test_passed:
        num_passed_tests += 1
      else:
        num_failed_tests += 1
      if num_failed_tests > max_fail_num: #test fails if number of failed tests greater than allowed
        if not already_failed:  # This value is False the first time we cross the threshold.
          logging.error('Just failed the maximum number of tests (%d).', num_failed_tests)
          already_failed = True
        if EARLY_EXIT_ENABLED:
          self.fail("Just failed the maximum number of tests (%d), quitting early." % num_failed_tests)

    # Outside the 'for' loop.
    logging.info('Passed %d out of %d tests. Need %2.6f percent pass rate.',
                 num_passed_tests, num_tests, test_pass_threshold * 100)
    self.assertTrue(num_passed_tests >= num_tests * test_pass_threshold)

<|endoftext|>