<commit_before>"""JSON endpoints."""
import functools
import inspect
import json

from werkzeug.routing import Map, Rule, Submount
from werkzeug.utils import ArgumentValidationError, validate_arguments
from werkzeug.wsgi import responder
from werkzeug.wrappers import Request, Response

class Encoder(json.JSONEncoder):
    """The default JSON encoder. When encoding objects, if the object
    has a :attribute:json property, it will be used instead of the
    object.

    >>> class Spam(object):
    ...     def json(self):
    ...         return 'eggs'
    ...
    >>> Encoder().encode({'spam': Spam()})
    '{"spam": "eggs"}'
    """
    def default(self, obj):
        try:
            encode = obj.json
        except AttributeError:
            return super(Encoder, self).default(obj)
        else:
            return encode()

class JSONRequest(Request):
    """A JSON request.

    >>> from werkzeug.test import EnvironBuilder
    >>> environ = EnvironBuilder(
    ...     content_type='application/json',
    ...     data='{"spam": 1, "eggs": 2}').get_environ()
    >>> d = JSONRequest(environ).json()
    >>> d['spam']
    1
    >>> d['eggs']
    2
    """
    max_content_length = 1024 * 1024 # 1MB

    def json(self):
        if self.headers.get('content-type') == 'application/json':
            return json.loads(self.get_data(as_text=True))

class JSONResponse(Response):
    """A JSON response.

    >>> class Spam(object):
    ...     def json(self):
    ...         return 'eggs'
    ...
    >>> response = JSONResponse({"spam": Spam()}, status=200)
    >>> response.content_type
    'application/json'
    >>> response.get_data()
    b'{"spam": "eggs"}'
    """
    def __init__(self, result, encoder=None, **kwds):
        super(JSONResponse, self).__init__(**kwds)
        if encoder is None:
            encoder = Encoder()
        self.response = encoder.iterencode(result)
        self.content_type = 'application/json'

class Endpoint:
    """An JSON endpoint that can be used as a normal function.

    :param string: The :class:Rule string.
    :param f: The wrapped function.
    :param response_handler: A function that, if present, will be
        called with the result of the wrapped function.
    :param error_handler: A function that, if present, will be
        called with any exception the wrapped function raises.
    :param kwds: Keyword arguments for :class:Rule.

    >>> from werkzeug.test import Client
    >>> def foo(x=0, y=0):
    ...     return {'result': x + y}
    ...
    >>> f = Endpoint('/<int:x>/', foo, encoder=Encoder(sort_keys=True))
    >>> str(f.rule)
    '/<int:x>/'
    >>> f(3, 2)
    {'result': 5}
    >>> c = Client(f.dispatch({"x": 3}), Response)
    >>> c.get('/', data='{"y": 2}',
    ...       content_type='application/json').data
    b'{"result": 5}'
    >>> c.get('/', data='{"y": "spam"}',
    ...       content_type='application/json').data # doctest: +ELLIPSIS
    b'{"message": "...", "status": 500}'
    """
    def __init__(self, string, f, encoder=None, **kwds):
        self.rule = Rule(string, endpoint=self, **kwds)
        self.f = f
        self.encoder = encoder
        functools.update_wrapper(self, f)

    def __call__(self, *args, **kwds):
        """Call the wrapped function normally."""
        return self.f(*args, **kwds)

    def dispatch(self, kwds):
        """Dispatch a request and pass URL arguments to the wrapped
        function. Any JSON object in the request body is passed as
        well if parsed correctly. Returns a WSGI application.
        """
        @responder
        def app(environ, start_reponse):
            status = None
            try:
                result = self._marshal(JSONRequest(environ), kwds)
            except Exception as e:
                try:
                    status = e.status
                except AttributeError:
                    status = 500 # Internal server error
                result = {
                    'status': status,
                    'message': str(e)
                }
            return JSONResponse(result, encoder=self.encoder, status=status)
        return app

    def _marshal(self, request, kwds):
        try:
            body = request.json()
            if isinstance(body, dict):
                kwds.update(body)
        except ValueError:
            pass
        try:
            args, kwds = validate_arguments(self.f, (), kwds)
        except ArgumentValidationError as e:
            raise BadRequest(e)
        return self.f(*args, **kwds)

def endpoint(string, **kwds):
    return functools.partial(Endpoint, string, **kwds)

class Dispatcher(object):
    """A WSGI application that dispatches requests to delegates.

    Each delegate is identified by a name. The delegate URLs are
    mounted in a submount identified by the delegate name.

    Delegate endpoints will be called with any dependencies they
    require, a Request object, and any keyword arguments from the
    URL. They should return a Response object.

    :param delegates: A dictionary of delegates.

    >>> from werkzeug.test import Client
    >>> from werkzeug.wrappers import Response
    >>> class Spam(object):
    ...     @endpoint('/<int:x>/', encoder=Encoder(sort_keys=True))
    ...     def foo(x=0):
    ...         return {'result': x + 2}
    ...
    >>> class Eggs(object):
    ...     @endpoint('/<string:s>/', encoder=Encoder(sort_keys=True))
    ...     def foo(s=''):
    ...         raise BadRequest(s)
    ...
    >>> dispatcher = Dispatcher({
    ...     'spam': Spam(),
    ...     'eggs': Eggs()
    ... })
    >>> c = Client(dispatcher, Response)
    >>> c.get('/spam/3/').data
    b'{"result": 5}'
    >>> c.get('/eggs/ni/').data
    b'{"message": "ni", "status": 400}'
    """
    def __init__(self, delegates):
        self.delegates = delegates
        self.url_map = Map([
            Submount('/' + name, [
                f.rule for _, f in inspect.getmembers(
                    delegate, lambda f: isinstance(f, Endpoint)
                )
            ])
            for name, delegate in self.delegates.items()
        ])

    @responder
    def __call__(self, environ, start_reponse):
        """Respond to a request."""
        urls = self.url_map.bind_to_environ(environ)
        return urls.dispatch(lambda f, kwds: f.dispatch(kwds))

class HTTPException(Exception):
    status = 400

class BadRequest(HTTPException):
    status = 400
<commit_msg>Some more exceptions<commit_after>"""JSON endpoints."""
import functools
import inspect
import json

from werkzeug.routing import Map, Rule, Submount
from werkzeug.utils import ArgumentValidationError, validate_arguments
from werkzeug.wsgi import responder
from werkzeug.wrappers import Request, Response

class Encoder(json.JSONEncoder):
    """The default JSON encoder. When encoding objects, if the object
    has a :attribute:json property, it will be used instead of the
    object.

    >>> class Spam(object):
    ...     def json(self):
    ...         return 'eggs'
    ...
    >>> Encoder().encode({'spam': Spam()})
    '{"spam": "eggs"}'
    """
    def default(self, obj):
        try:
            encode = obj.json
        except AttributeError:
            return super(Encoder, self).default(obj)
        else:
            return encode()

class JSONRequest(Request):
    """A JSON request.

    >>> from werkzeug.test import EnvironBuilder
    >>> environ = EnvironBuilder(
    ...     content_type='application/json',
    ...     data='{"spam": 1, "eggs": 2}').get_environ()
    >>> d = JSONRequest(environ).json()
    >>> d['spam']
    1
    >>> d['eggs']
    2
    """
    max_content_length = 1024 * 1024 # 1MB

    def json(self):
        if self.headers.get('content-type') == 'application/json':
            return json.loads(self.get_data(as_text=True))

class JSONResponse(Response):
    """A JSON response.

    >>> class Spam(object):
    ...     def json(self):
    ...         return 'eggs'
    ...
    >>> response = JSONResponse({"spam": Spam()}, status=200)
    >>> response.content_type
    'application/json'
    >>> response.get_data()
    b'{"spam": "eggs"}'
    """
    def __init__(self, result, encoder=None, **kwds):
        super(JSONResponse, self).__init__(**kwds)
        if encoder is None:
            encoder = Encoder()
        self.response = encoder.iterencode(result)
        self.content_type = 'application/json'

class Endpoint:
    """An JSON endpoint that can be used as a normal function.

    :param string: The :class:Rule string.
    :param f: The wrapped function.
    :param response_handler: A function that, if present, will be
        called with the result of the wrapped function.
    :param error_handler: A function that, if present, will be
        called with any exception the wrapped function raises.
    :param kwds: Keyword arguments for :class:Rule.

    >>> from werkzeug.test import Client
    >>> def foo(x=0, y=0):
    ...     return {'result': x + y}
    ...
    >>> f = Endpoint('/<int:x>/', foo, encoder=Encoder(sort_keys=True))
    >>> str(f.rule)
    '/<int:x>/'
    >>> f(3, 2)
    {'result': 5}
    >>> c = Client(f.dispatch({"x": 3}), Response)
    >>> c.get('/', data='{"y": 2}',
    ...       content_type='application/json').data
    b'{"result": 5}'
    >>> c.get('/', data='{"y": "spam"}',
    ...       content_type='application/json').data # doctest: +ELLIPSIS
    b'{"message": "...", "status": 500}'
    """
    def __init__(self, string, f, encoder=None, **kwds):
        self.rule = Rule(string, endpoint=self, **kwds)
        self.f = f
        self.encoder = encoder
        functools.update_wrapper(self, f)

    def __call__(self, *args, **kwds):
        """Call the wrapped function normally."""
        return self.f(*args, **kwds)

    def dispatch(self, kwds):
        """Dispatch a request and pass URL arguments to the wrapped
        function. Any JSON object in the request body is passed as
        well if parsed correctly. Returns a WSGI application.
        """
        @responder
        def app(environ, start_reponse):
            status = None
            try:
                result = self._marshal(JSONRequest(environ), kwds)
            except Exception as e:
                try:
                    status = e.status
                except AttributeError:
                    status = 500 # Internal server error
                result = {
                    'status': status,
                    'message': str(e)
                }
            return JSONResponse(result, encoder=self.encoder, status=status)
        return app

    def _marshal(self, request, kwds):
        try:
            body = request.json()
            if isinstance(body, dict):
                kwds.update(body)
        except ValueError:
            pass
        try:
            args, kwds = validate_arguments(self.f, (), kwds)
        except ArgumentValidationError as e:
            raise BadRequest(e)
        return self.f(*args, **kwds)

def endpoint(string, **kwds):
    return functools.partial(Endpoint, string, **kwds)

class Dispatcher(object):
    """A WSGI application that dispatches requests to delegates.

    Each delegate is identified by a name. The delegate URLs are
    mounted in a submount identified by the delegate name.

    Delegate endpoints will be called with any dependencies they
    require, a Request object, and any keyword arguments from the
    URL. They should return a Response object.

    :param delegates: A dictionary of delegates.

    >>> from werkzeug.test import Client
    >>> from werkzeug.wrappers import Response
    >>> class Spam(object):
    ...     @endpoint('/<int:x>/', encoder=Encoder(sort_keys=True))
    ...     def foo(x=0):
    ...         return {'result': x + 2}
    ...
    >>> class Eggs(object):
    ...     @endpoint('/<string:s>/', encoder=Encoder(sort_keys=True))
    ...     def foo(s=''):
    ...         raise BadRequest(s)
    ...
    >>> dispatcher = Dispatcher({
    ...     'spam': Spam(),
    ...     'eggs': Eggs()
    ... })
    >>> c = Client(dispatcher, Response)
    >>> c.get('/spam/3/').data
    b'{"result": 5}'
    >>> c.get('/eggs/ni/').data
    b'{"message": "ni", "status": 400}'
    """
    def __init__(self, delegates):
        self.delegates = delegates
        self.url_map = Map([
            Submount('/' + name, [
                f.rule for _, f in inspect.getmembers(
                    delegate, lambda f: isinstance(f, Endpoint)
                )
            ])
            for name, delegate in self.delegates.items()
        ])

    @responder
    def __call__(self, environ, start_reponse):
        """Respond to a request."""
        urls = self.url_map.bind_to_environ(environ)
        return urls.dispatch(lambda f, kwds: f.dispatch(kwds))

class HTTPException(Exception):
    status = 400

class BadRequest(HTTPException):
    status = 400

class InternalServerError(HTTPException):
    status = 502

class BadGateway(HTTPException):
    status = 502
<|endoftext|>


<commit_before># ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (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.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is l10n django site.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#   Zbigniew Braniecki <gandalf@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****

from webby.models import Project, ProjectType, Weblocale
from django.contrib import admin

class WeblocaleInline(admin.TabularInline):
    model = Weblocale

class ProjectAdmin(admin.ModelAdmin):
    inlines = [WeblocaleInline, ]

class WeblocaleAdmin(admin.ModelAdmin):
    list_display = ['__unicode__', 'requestee', 'in_verbatim', 'in_vcs',
                    'is_on_stage', 'is_on_prod']
    list_display_links = ['__unicode__']
    list_editable = ['in_verbatim', 'in_vcs', 'is_on_stage', 'is_on_prod']
    list_filter = ['project']
    search_fields = ['project__name', 'project__slug', 'locale__code',
                     'locale__name']

admin.site.register(ProjectType)
admin.site.register(Project, ProjectAdmin)
admin.site.register(Weblocale, WeblocaleAdmin)
<commit_msg>No bug, add prepopulated_fields to ProjectAdmin for the slug<commit_after># ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (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.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is l10n django site.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#   Zbigniew Braniecki <gandalf@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****

from webby.models import Project, ProjectType, Weblocale
from django.contrib import admin

class WeblocaleInline(admin.TabularInline):
    model = Weblocale

class ProjectAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("name",)}
    inlines = [WeblocaleInline, ]

class WeblocaleAdmin(admin.ModelAdmin):
    list_display = ['__unicode__', 'requestee', 'in_verbatim', 'in_vcs',
                    'is_on_stage', 'is_on_prod']
    list_display_links = ['__unicode__']
    list_editable = ['in_verbatim', 'in_vcs', 'is_on_stage', 'is_on_prod']
    list_filter = ['project']
    search_fields = ['project__name', 'project__slug', 'locale__code',
                     'locale__name']

admin.site.register(ProjectType)
admin.site.register(Project, ProjectAdmin)
admin.site.register(Weblocale, WeblocaleAdmin)
<|endoftext|>


<commit_before>import datetime
import os

import pytz
import requests
from flask import g, jsonify, request
from penn.base import APIError
from sqlalchemy import and_, func

from server import app, sqldb
from server.account import get_courses_in_N_days, get_todays_courses
from server.auth import auth
from server.calendar3year import pull_todays_calendar
from server.models import Account, DiningPreference, Event, HomeCell, LaundryPreference, User
from server.news import fetch_frontpage_article
from server.portal.posts import get_posts_for_account
from server.studyspaces.models import StudySpacesBooking
from server.studyspaces.reservations import get_reservations

utc = pytz.timezone('UTC')
eastern = pytz.timezone('US/Eastern')

@app.route('/appversion/iOS', methods=['POST'])
def update_app_version():
    secret = os.environ.get('AUTH_SECRET')
    auth_secret = request.form.get('auth_secret')
    if auth_secret is None:
        return jsonify({'error': 'Auth secret is not provided.'}), 400
    if not auth_secret == secret:
        return jsonify({'error': 'Auth secret is not correct.'}), 400

    version = request.form.get('version')
    if version is None:
        return jsonify({'err': 'No version passed to server'}), 400

    os.environ['APP_VERSION'] = version
    return jsonify({'success': 'App version has been updated to ' + version})

@app.route('/appversion/iOS', methods=['GET'])
def get_app_version():
    version = os.environ.get('APP_VERSION')
    return jsonify({'version': version})

@app.route('/homepage', methods=['GET'])
@auth(nullable=True)
def get_homepage():
    # Find user in database
    try:
        user = User.get_or_create()
    except ValueError as e:
        response = jsonify({'err': [str(e)]})
        response.status_code = 400
        return response

    account = g.account
    if not account:
        try:
            account = Account.get_account()
        except ValueError:
            account = None

    if account and account.email and user.email is None:
        user.email = account.email
        sqldb.session.commit()

    cells = []

    sessionid = request.args.get('sessionid')
    reservations_cell = get_reservations_cell(user, sessionid)
    if reservations_cell:
        cells.append(reservations_cell)

    version = request.args.get('version')

    # if account and account.is_student():
    #     courses = get_courses_cell(account)
    #     if courses:
    #         cells.append(courses)

    laundry = get_top_laundry_cell(user)
    dining = get_dining_cell(user)
    cells.extend([dining, laundry])

    gsr_locations = get_gsr_locations_cell(user, account)
    cells.append(gsr_locations)

    app_version = os.environ.get('APP_VERSION')

    if version and version < app_version:
        update_cell = get_version_cell(version)
        cells.append(update_cell)

    calendar = get_university_event_cell()
    if calendar:
        cells.append(calendar)

    news = get_news_cell()
    if news:
        cells.append(news)

    feature = get_feature_announcement_cell()
    if feature:
        cells.append(feature)

    posts = get_post_cells(account)
    if posts:
        cells.extend(posts)

    cells.sort(key=lambda x: x.weight, reverse=True)

    response = jsonify({'cells': [x.getCell() for x in cells]})
    response.status_code = 200
    return response

def get_dining_cell(user):
    # returns a dining cell
    preferences = sqldb.session.query(DiningPreference.venue_id).filter_by(user_id=user.id)
    venue_ids = [x.venue_id for x in preferences]
    defaults_ids = [593, 1442, 636]
    if len(venue_ids) == 0:
        venue_ids = defaults_ids
    elif len(venue_ids) == 1:
        venue_ids.extend(defaults_ids)
        venue_ids = list(set(venue_ids))[:3]

    info = {'venues': venue_ids}
    return HomeCell('dining', info, 100)

def get_laundry_cells(user):
    # returns a list of laundry cells
    preferences = LaundryPreference.query.filter_by(user_id=user.id)
    room_ids = [x.room_id for x in preferences]

    # If the user has no preferences, select Bishop White
    if not room_ids:
        room_ids.append(0)

    return [HomeCell('laundry', {'room_id': x}) for x in room_ids]

def get_top_laundry_cell(user):
    # returns user's top laundry cell
    top_preference = LaundryPreference.query.filter_by(user_id=user.id).first()
    # If no top choice, select bishop white
    if top_preference:
        return HomeCell('laundry', {'room_id': top_preference.room_id}, 5)
    return HomeCell('laundry', {'room_id': 0}, 5)

def get_gsr_locations_cell(user, account):
    # returns a gsr cell with list of locations
    # if student is a Wharton student, show at the top
    top_gsrs_query = sqldb.session.query(StudySpacesBooking.lid) \
                                  .filter(and_(StudySpacesBooking.user == user.id,
                                               StudySpacesBooking.lid.isnot(None))) \
                                  .group_by(StudySpacesBooking.lid) \
                                  .order_by(func.count(StudySpacesBooking.lid).desc()) \
                                  .limit(2) \
                                  .all()
    preferences = [x for (x,) in top_gsrs_query]

    showHuntsman = account is None or account.email is None or 'wharton' in account.email
    if showHuntsman:
        default_gids = [1, 1086]
        weighting = 300
    else:
        default_gids = [1086, 2587]
        weighting = 10

    # Remove duplicates while retaining relative ordering
    def f7(seq):
        seen = set()
        seen_add = seen.add
        return [x for x in seq if not (x in seen or seen_add(x))]

    gids = f7(preferences + default_gids)[:2]
    return HomeCell('gsr-locations', gids, weighting)

def get_university_event_cell():
    # returns a university notification cell
    calendar = pull_todays_calendar()
    if calendar:
        return HomeCell('calendar', calendar, 40)
    else:
        return None

def get_news_cell():
    # returns a news cell
    article = fetch_frontpage_article()
    if article:
        return HomeCell('news', article, 50)
    else:
        return None

def get_event_cell():
    # return a event cell
    # TODO Fetch most recent, most popular, etc
    event = Event.query.first()
    if event:
        info = {
            'name': event.name,
            'description': event.description,
            'image_url': event.image_url,
            'start_time': utc.localize(event.start_time).astimezone(eastern).isoformat(),
            'end_time': utc.localize(event.end_time).astimezone(eastern).isoformat(),
            'email': event.email,
            'website': event.website,
            'facebook': event.facebook
        }
        return HomeCell('event', info)
    else:
        return None

def get_feature_announcement_cell():
    # returns an announcement for a new Penn Mobile feature
    now = datetime.datetime.now().date()
    start = datetime.date(2019, 4, 12)
    end = datetime.date(2019, 4, 13)
    if now < start or now > end:
        return None

    info = {
        'source': 'Spring Fling',
        'title': 'Tap to view the Fling schedule, performers, and more!',
        'description': None,
        'timestamp': 'Saturday 4/13',
        'image_url': 'ADD IMAGE HERE',
        'feature': 'Spring Fling',
    }
    return HomeCell('feature', info, 2000)

def get_courses_cell(account):
    # return a cell containing today's courses
    courses = get_todays_courses(account)

    # Return today's courses if last course has not yet ended
    now = datetime.datetime.now()
    weekday = int(now.strftime('%w'))
    if courses:
        for course in courses:
            end_time = datetime.datetime.strptime(course['end_time'], '%I:%M %p')
            if now.hour < end_time.hour or (now.hour == end_time.hour and now.minute < end_time.minute):
                return HomeCell('courses', {'weekday': 'Today', 'courses': courses}, 200)
    elif weekday == 6:
        # Return Monday's courses if today is Saturday
        courses = get_courses_in_N_days(account, 2)
        return HomeCell('courses', {'weekday': 'Monday', 'courses': courses}, 30)
    elif weekday != 0:
        # Return empty cell if there are no courses today and today isn't Saturday or Sunday
        return HomeCell('courses', {'weekday': 'Today', 'courses': []}, 30)

    # Return tomorrow's courses if today's last course has ended
    courses = get_courses_in_N_days(account, 1)
    return HomeCell('courses', {'weekday': 'Tomorrow', 'courses': courses}, 30)

def get_reservations_cell(user, sessionid):
    # returns a cell with the user's reservations, weighted extremely high to appear at the top
    # returns None if user has no reservations
    try:
        reservations = get_reservations(user.email, sessionid, 1, 2)
        if reservations:
            return HomeCell('reservations', reservations, 1000)
        else:
            return None
    except APIError:
        return None
    except requests.exceptions.Timeout:
        return None

def get_post_cells(account):
    posts = get_posts_for_account(account)
    cells = []
    for post in posts:
        cell = HomeCell('post', post, 15000)
        cells.append(cell)
    return cells

def get_version_cell(version):
    return HomeCell('new-version-released', None, 10000)
<commit_msg>removed events<commit_after>import datetime
import os

import requests
from flask import g, jsonify, request
from penn.base import APIError
from sqlalchemy import and_, func

from server import app, sqldb
from server.account import get_courses_in_N_days, get_todays_courses
from server.auth import auth
from server.calendar3year import pull_todays_calendar
from server.models import Account, DiningPreference, Event, HomeCell, LaundryPreference, User
from server.news import fetch_frontpage_article
from server.portal.posts import get_posts_for_account
from server.studyspaces.models import StudySpacesBooking
from server.studyspaces.reservations import get_reservations

@app.route('/appversion/iOS', methods=['POST'])
def update_app_version():
    secret = os.environ.get('AUTH_SECRET')
    auth_secret = request.form.get('auth_secret')
    if auth_secret is None:
        return jsonify({'error': 'Auth secret is not provided.'}), 400
    if not auth_secret == secret:
        return jsonify({'error': 'Auth secret is not correct.'}), 400

    version = request.form.get('version')
    if version is None:
        return jsonify({'err': 'No version passed to server'}), 400

    os.environ['APP_VERSION'] = version
    return jsonify({'success': 'App version has been updated to ' + version})

@app.route('/appversion/iOS', methods=['GET'])
def get_app_version():
    version = os.environ.get('APP_VERSION')
    return jsonify({'version': version})

@app.route('/homepage', methods=['GET'])
@auth(nullable=True)
def get_homepage():
    # Find user in database
    try:
        user = User.get_or_create()
    except ValueError as e:
        response = jsonify({'err': [str(e)]})
        response.status_code = 400
        return response

    account = g.account
    if not account:
        try:
            account = Account.get_account()
        except ValueError:
            account = None

    if account and account.email and user.email is None:
        user.email = account.email
        sqldb.session.commit()

    cells = []

    sessionid = request.args.get('sessionid')
    reservations_cell = get_reservations_cell(user, sessionid)
    if reservations_cell:
        cells.append(reservations_cell)

    version = request.args.get('version')

    # if account and account.is_student():
    #     courses = get_courses_cell(account)
    #     if courses:
    #         cells.append(courses)

    laundry = get_top_laundry_cell(user)
    dining = get_dining_cell(user)
    cells.extend([dining, laundry])

    gsr_locations = get_gsr_locations_cell(user, account)
    cells.append(gsr_locations)

    app_version = os.environ.get('APP_VERSION')

    if version and version < app_version:
        update_cell = get_version_cell(version)
        cells.append(update_cell)

    calendar = get_university_event_cell()
    if calendar:
        cells.append(calendar)

    news = get_news_cell()
    if news:
        cells.append(news)

    feature = get_feature_announcement_cell()
    if feature:
        cells.append(feature)

    posts = get_post_cells(account)
    if posts:
        cells.extend(posts)

    cells.sort(key=lambda x: x.weight, reverse=True)

    response = jsonify({'cells': [x.getCell() for x in cells]})
    response.status_code = 200
    return response

def get_dining_cell(user):
    # returns a dining cell
    preferences = sqldb.session.query(DiningPreference.venue_id).filter_by(user_id=user.id)
    venue_ids = [x.venue_id for x in preferences]
    defaults_ids = [593, 1442, 636]
    if len(venue_ids) == 0:
        venue_ids = defaults_ids
    elif len(venue_ids) == 1:
        venue_ids.extend(defaults_ids)
        venue_ids = list(set(venue_ids))[:3]

    info = {'venues': venue_ids}
    return HomeCell('dining', info, 100)

def get_laundry_cells(user):
    # returns a list of laundry cells
    preferences = LaundryPreference.query.filter_by(user_id=user.id)
    room_ids = [x.room_id for x in preferences]

    # If the user has no preferences, select Bishop White
    if not room_ids:
        room_ids.append(0)

    return [HomeCell('laundry', {'room_id': x}) for x in room_ids]

def get_top_laundry_cell(user):
    # returns user's top laundry cell
    top_preference = LaundryPreference.query.filter_by(user_id=user.id).first()
    # If no top choice, select bishop white
    if top_preference:
        return HomeCell('laundry', {'room_id': top_preference.room_id}, 5)
    return HomeCell('laundry', {'room_id': 0}, 5)

def get_gsr_locations_cell(user, account):
    # returns a gsr cell with list of locations
    # if student is a Wharton student, show at the top
    top_gsrs_query = sqldb.session.query(StudySpacesBooking.lid) \
                                  .filter(and_(StudySpacesBooking.user == user.id,
                                               StudySpacesBooking.lid.isnot(None))) \
                                  .group_by(StudySpacesBooking.lid) \
                                  .order_by(func.count(StudySpacesBooking.lid).desc()) \
                                  .limit(2) \
                                  .all()
    preferences = [x for (x,) in top_gsrs_query]

    showHuntsman = account is None or account.email is None or 'wharton' in account.email
    if showHuntsman:
        default_gids = [1, 1086]
        weighting = 300
    else:
        default_gids = [1086, 2587]
        weighting = 10

    # Remove duplicates while retaining relative ordering
    def f7(seq):
        seen = set()
        seen_add = seen.add
        return [x for x in seq if not (x in seen or seen_add(x))]

    gids = f7(preferences + default_gids)[:2]
    return HomeCell('gsr-locations', gids, weighting)

def get_university_event_cell():
    # returns a university notification cell
    calendar = pull_todays_calendar()
    if calendar:
        return HomeCell('calendar', calendar, 40)
    else:
        return None

def get_news_cell():
    # returns a news cell
    article = fetch_frontpage_article()
    if article:
        return HomeCell('news', article, 50)
    else:
        return None

def get_feature_announcement_cell():
    # returns an announcement for a new Penn Mobile feature
    now = datetime.datetime.now().date()
    start = datetime.date(2019, 4, 12)
    end = datetime.date(2019, 4, 13)
    if now < start or now > end:
        return None

    info = {
        'source': 'Spring Fling',
        'title': 'Tap to view the Fling schedule, performers, and more!',
        'description': None,
        'timestamp': 'Saturday 4/13',
        'image_url': 'ADD IMAGE HERE',
        'feature': 'Spring Fling',
    }
    return HomeCell('feature', info, 2000)

def get_courses_cell(account):
    # return a cell containing today's courses
    courses = get_todays_courses(account)

    # Return today's courses if last course has not yet ended
    now = datetime.datetime.now()
    weekday = int(now.strftime('%w'))
    if courses:
        for course in courses:
            end_time = datetime.datetime.strptime(course['end_time'], '%I:%M %p')
            if now.hour < end_time.hour or (now.hour == end_time.hour and now.minute < end_time.minute):
                return HomeCell('courses', {'weekday': 'Today', 'courses': courses}, 200)
    elif weekday == 6:
        # Return Monday's courses if today is Saturday
        courses = get_courses_in_N_days(account, 2)
        return HomeCell('courses', {'weekday': 'Monday', 'courses': courses}, 30)
    elif weekday != 0:
        # Return empty cell if there are no courses today and today isn't Saturday or Sunday
        return HomeCell('courses', {'weekday': 'Today', 'courses': []}, 30)

    # Return tomorrow's courses if today's last course has ended
    courses = get_courses_in_N_days(account, 1)
    return HomeCell('courses', {'weekday': 'Tomorrow', 'courses': courses}, 30)

def get_reservations_cell(user, sessionid):
    # returns a cell with the user's reservations, weighted extremely high to appear at the top
    # returns None if user has no reservations
    try:
        reservations = get_reservations(user.email, sessionid, 1, 2)
        if reservations:
            return HomeCell('reservations', reservations, 1000)
        else:
            return None
    except APIError:
        return None
    except requests.exceptions.Timeout:
        return None

def get_post_cells(account):
    posts = get_posts_for_account(account)
    cells = []
    for post in posts:
        cell = HomeCell('post', post, 15000)
        cells.append(cell)
    return cells

def get_version_cell(version):
    return HomeCell('new-version-released', None, 10000)
<|endoftext|>


<commit_before>#!/usr/bin/env python

# pylint: disable=W0703

import os
import types
import logging
import weakref

import cle
import simuvex
import archinfo

l = logging.getLogger("angr.project")

projects = weakref.WeakValueDictionary()
def fake_project_unpickler(name):
    if name not in projects:
        raise AngrError("Project %s has not been opened." % name)
    return projects[name]
fake_project_unpickler.__safe_for_unpickling__ = True

def deprecated(f):
    def deprecated_wrapper(*args, **kwargs):
        print "ERROR: FUNCTION %s IS DEPRECATED. PLEASE UPDATE YOUR CODE." % f
        return f(*args, **kwargs)
    return deprecated_wrapper

class Project(object):
    """
    This is the main class of the Angr module. It is meant to contain a set of
    binaries and the relationships between them, and perform analyses on them.
    """

    def __init__(self, thing,
                 default_analysis_mode=None,
                 ignore_functions=None,
                 use_sim_procedures=True,
                 exclude_sim_procedures_func=None,
                 exclude_sim_procedures_list=(),
                 arch=None, simos=None,
                 load_options=None,
                 parallel=False,
                 support_selfmodifying_code=False):
        """
        This constructs a Project object.

        Arguments:
         @param thing
             the path to the main executable object to analyze, or a CLE Loader object
         @param default_analysis_mode
             the mode of analysis to use by default. Defaults to 'symbolic'.
         @param ignore_functions
             a list of function names that, when imported from shared libraries,
             should never be stepped into in analysis (calls will return an
             unconstrained value)
         @param use_sim_procedure
             whether to replace resolved dependencies for which simprocedures
             are available with said simprocedures
         @param exclude_sim_procedures_func
             a function that, when passed a function name, returns whether
             or not to wrap it with a simprocedure
         @param exclude_sim_procedures_list
             a list of functions to *not* wrap with simprocedures
         @param arch
             optional target architecture (auto-detected otherwise)
             in the form of an archinfo.Arch or a string
         @param simos
             a SimOS class to use for this project
         @param load_options
             a dict of keyword arguments to the CLE loader. See CLE's docs.
             e.g., { 'auto_load_libs': False,
                     'skip_libs': 'ld.so.2',
                     'lib_opts': {
                       'libc.so.6': {
                         'custom_base_addr': 0x55555400
                       }
                     }
                   }
         @param parallel
             whether to use parallel processing analyzing this binary
         @param support_selfmodifying_code
             Whether we support self-modifying code. When enabled, Project.sim_block() will try to read code from the
             given state, not only from the initial memory regions.
        """

        # Step 1: Load the binary
        if isinstance(thing, cle.Loader):
            l.warning("Passing a CLE object as the `thing` argument to Project causes the resulting object to be un-serializable.")
            self._load_options = None
            self.loader = thing
            self.filename = self.loader._main_binary_path
        elif not isinstance(thing, (unicode, str)) or not os.path.exists(thing) or not os.path.isfile(thing):
            raise Exception("Not a valid binary file: %s" % repr(thing))
        else:
            # use angr's loader, provided by cle
            l.info("Loading binary %s", thing)
            self.filename = thing
            self._load_options = { } if load_options is None else load_options
            self.loader = cle.Loader(self.filename, **self._load_options)

        # Step 2: determine its CPU architecture, ideally falling back to CLE's guess
        if isinstance(arch, str):
            self.arch = archinfo.arch_from_id(arch) # may raise ArchError, let the user see this
        elif isinstance(arch, archinfo.Arch):
            self.arch = arch
        elif arch is None:
            self.arch = self.loader.main_bin.arch
        else:
            raise ValueError("Invalid arch specification.")

        # Step 3: Set some defaults and set the public and private properties
        if not default_analysis_mode:
            default_analysis_mode = 'symbolic'
        if not ignore_functions:
            ignore_functions = []

        if isinstance(exclude_sim_procedures_func, types.LambdaType):
            l.warning("Passing a lambda type as the exclude_sim_procedures_func argument to Project causes the resulting object to be un-serializable.")

        self._sim_procedures = {}
        self._default_analysis_mode = default_analysis_mode
        self._exclude_sim_procedures_func = exclude_sim_procedures_func
        self._exclude_sim_procedures_list = exclude_sim_procedures_list
        self._should_use_sim_procedures = use_sim_procedures
        self._parallel = parallel
        self._support_selfmodifying_code = support_selfmodifying_code
        self._ignore_functions = ignore_functions
        self._extern_obj = AngrExternObject()
        self.loader.add_object(self._extern_obj)

        self._cfg = None
        self._vfg = None
        self._cdg = None

        self.entry = self.loader.main_bin.entry
        self.factory = AngrObjectFactory(self)
        self.analyses = Analyses(self)
        self.surveyors = Surveyors(self)

        projects[self.filename] = self

        # Step 4: Register simprocedures as appropriate for library functions
        self._use_sim_procedures()

        # Step 5: determine the host OS and perform additional initialization
        # in the SimOS constructor
        if isinstance(simos, type) and issubclass(simos, SimOS):
            self._simos = simos(self) #pylint:disable=invalid-name
        elif simos is None:
            self._simos = os_mapping[self.loader.main_bin.os](self)
        else:
            raise ValueError("Invalid OS specification or non-matching architecture.")

    #
    # Public methods
    #

    def hook(self, addr, func, length=0, kwargs=None):
        """
         Hook a section of code with a custom function.

         @param addr        The address to hook
         @param func        A python function or SimProcedure class that will perform an action when
                            execution reaches the hooked address
         @param length      How many bytes you'd like to skip over with your hook. Can be zero.
         @param kwargs      A dictionary of keyword arguments to be passed to your function or
                            your SimProcedure's run function.

         If func is a function, it takes a SimState and the given kwargs. It can return nothing
         (None), in which case it will generate a single exit to the instruction at addr+length,
         or it can return an array of successor states.

         If func is a SimProcedure, it will be run instead of a SimBlock at that address.

         If length is zero, the block at the hooked address will be executed immediately
         after the hook function.
        """

        if self.is_hooked(addr):
            l.warning("Address is already hooked [hook(%#x, %s)]", addr, func)
            return

        if kwargs is None: kwargs = {}

        if isinstance(func, type):
            proc = func
        elif hasattr(func, '__call__'):
            proc = simuvex.procedures.stubs.UserHook.UserHook
            kwargs = {'user_func': func, 'user_kwargs': kwargs, 'default_return_addr': addr+length}
        else:
            raise AngrError("%s is not a valid object to execute in a hook", func)

        self._sim_procedures[addr] = (proc, kwargs)

    def is_hooked(self, addr):
        return addr in self._sim_procedures

    def unhook(self, addr):
        if not self.is_hooked(addr):
            l.warning("Address %#x not hooked", addr)
            return

        del self._sim_procedures[addr]

    #
    # Pickling
    #

    def __getstate__(self):
        try:
            factory, analyses, surveyors = self.factory, self.analyses, self.surveyors
            self.factory, self.analyses, self.surveyors = None, None, None
            return dict(self.__dict__)
        finally:
            self.factory, self.analyses, self.surveyors = factory, analyses, surveyors

    def __setstate__(self, s):
        self.__dict__.update(s)
        self.factory = AngrObjectFactory(self)
        self.analyses = Analyses(self)
        self.surveyors = Surveyors(self)

    #
    # Private project stuff for simprocedures
    #

    def _should_exclude_sim_procedure(self, f):
        return (f in self._exclude_sim_procedures_list) or \
               ( self._exclude_sim_procedures_func is not None and \
                 self._exclude_sim_procedures_func(f)
               )

    def _find_sim_libraries(self):
        """ Look for libaries that we can replace with their simuvex
        simprocedures counterpart
        This function returns the list of libraries that were found in simuvex
        """
        simlibs = []

        for lib_name in self.loader.requested_objects:
            # Hack that should go somewhere else:
            if lib_name == 'libc.so.0':
                lib_name = 'libc.so.6'

            if lib_name == 'ld-uClibc.so.0':
                lib_name = 'ld-uClibc.so.6'

            if lib_name not in simuvex.procedures.SimProcedures:
                l.debug("There are no simprocedures for library %s :(", lib_name)
            else:
                simlibs.append(lib_name)

        return simlibs

    def _use_sim_procedures(self):
        """ Use simprocedures where we can """
        libs = self._find_sim_libraries()
        for obj in self.loader.all_objects:
            unresolved = []
            for reloc in obj.imports.itervalues():
                func = reloc.symbol
                if not func.is_function:
                    continue
                elif func.name in self._ignore_functions:
                    unresolved.append(func)
                    continue
                elif self._should_exclude_sim_procedure(func.name):
                    continue

                elif self._should_use_sim_procedures:
                    for lib in libs:
                        simfun = simuvex.procedures.SimProcedures[lib]
                        if func.name in simfun:
                            l.info("[R] %s:", func.name)
                            l.debug("\t -> matching SimProcedure in %s :)", lib)
                            self.set_sim_procedure(obj, func.name, simfun[func.name], None)
                            break
                    else: # we could not find a simprocedure for this function
                        if not func.resolved:   # the loader couldn't find one either
                            unresolved.append(func)
                # in the case that simprocedures are off and an object in the PLT goes
                # unresolved, we still want to replace it with a retunconstrained.
                elif not func.resolved and func.name in obj.jmprel:
                    unresolved.append(func)

            for func in unresolved:
                # Don't touch weakly bound symbols, they are allowed to go unresolved
                if func.is_weak:
                    continue
                l.info("[U] %s", func.name)
                procedure = simuvex.SimProcedures['stubs']['NoReturnUnconstrained']
                if func.name not in procedure.use_cases:
                    procedure = simuvex.SimProcedures['stubs']['ReturnUnconstrained']
                self.set_sim_procedure(obj, func.name, procedure, {'resolves': func.name})

    def set_sim_procedure(self, binary, func_name, sim_proc, kwargs=None):
        """
         Use a simprocedure to resolve a dependency in a binary.

         @param binary      The CLE binary whose dependency is to be resolve
         @param func_name   The name of the dependency to resolve
         @param sim_proc    The class of the SimProcedure to use
         @param kwargs      An optional dictionary of arguments to be passed
                            to the simprocedure's run() method.
        """
        if kwargs is None: kwargs = {}
        ident = sim_proc.__module__ + '.' + sim_proc.__name__
        if 'resolves' in kwargs:
            ident += '.' + kwargs['resolves']
        pseudo_addr = self._extern_obj.get_pseudo_addr(ident)
        binary.set_got_entry(func_name, pseudo_addr)

        if not self.is_hooked(pseudo_addr):     # Do not add duplicate simprocedures
            self.hook(pseudo_addr, sim_proc, kwargs=kwargs)
            l.debug("\t -> setting SimProcedure with pseudo_addr 0x%x...", pseudo_addr)

from .errors import AngrError
from .factory import AngrObjectFactory
from .simos import SimOS, os_mapping
from .extern_obj import AngrExternObject
from .analysis import Analyses
from .surveyor import Surveyors
<commit_msg>Remove an unnecissary warning/private property now that loaders are pickleable<commit_after>#!/usr/bin/env python

# pylint: disable=W0703

import os
import types
import logging
import weakref

import cle
import simuvex
import archinfo

l = logging.getLogger("angr.project")

projects = weakref.WeakValueDictionary()
def fake_project_unpickler(name):
    if name not in projects:
        raise AngrError("Project %s has not been opened." % name)
    return projects[name]
fake_project_unpickler.__safe_for_unpickling__ = True

def deprecated(f):
    def deprecated_wrapper(*args, **kwargs):
        print "ERROR: FUNCTION %s IS DEPRECATED. PLEASE UPDATE YOUR CODE." % f
        return f(*args, **kwargs)
    return deprecated_wrapper

class Project(object):
    """
    This is the main class of the Angr module. It is meant to contain a set of
    binaries and the relationships between them, and perform analyses on them.
    """

    def __init__(self, thing,
                 default_analysis_mode=None,
                 ignore_functions=None,
                 use_sim_procedures=True,
                 exclude_sim_procedures_func=None,
                 exclude_sim_procedures_list=(),
                 arch=None, simos=None,
                 load_options=None,
                 parallel=False,
                 support_selfmodifying_code=False):
        """
        This constructs a Project object.

        Arguments:
         @param thing
             the path to the main executable object to analyze, or a CLE Loader object
         @param default_analysis_mode
             the mode of analysis to use by default. Defaults to 'symbolic'.
         @param ignore_functions
             a list of function names that, when imported from shared libraries,
             should never be stepped into in analysis (calls will return an
             unconstrained value)
         @param use_sim_procedure
             whether to replace resolved dependencies for which simprocedures
             are available with said simprocedures
         @param exclude_sim_procedures_func
             a function that, when passed a function name, returns whether
             or not to wrap it with a simprocedure
         @param exclude_sim_procedures_list
             a list of functions to *not* wrap with simprocedures
         @param arch
             optional target architecture (auto-detected otherwise)
             in the form of an archinfo.Arch or a string
         @param simos
             a SimOS class to use for this project
         @param load_options
             a dict of keyword arguments to the CLE loader. See CLE's docs.
             e.g., { 'auto_load_libs': False,
                     'skip_libs': 'ld.so.2',
                     'lib_opts': {
                       'libc.so.6': {
                         'custom_base_addr': 0x55555400
                       }
                     }
                   }
         @param parallel
             whether to use parallel processing analyzing this binary
         @param support_selfmodifying_code
             Whether we support self-modifying code. When enabled, Project.sim_block() will try to read code from the
             given state, not only from the initial memory regions.
        """

        # Step 1: Load the binary
        if isinstance(thing, cle.Loader):
            self.loader = thing
            self.filename = self.loader._main_binary_path
        elif not isinstance(thing, (unicode, str)) or not os.path.exists(thing) or not os.path.isfile(thing):
            raise Exception("Not a valid binary file: %s" % repr(thing))
        else:
            # use angr's loader, provided by cle
            l.info("Loading binary %s", thing)
            self.filename = thing
            if load_options is None: load_options = {}
            self.loader = cle.Loader(self.filename, **load_options)

        # Step 2: determine its CPU architecture, ideally falling back to CLE's guess
        if isinstance(arch, str):
            self.arch = archinfo.arch_from_id(arch) # may raise ArchError, let the user see this
        elif isinstance(arch, archinfo.Arch):
            self.arch = arch
        elif arch is None:
            self.arch = self.loader.main_bin.arch
        else:
            raise ValueError("Invalid arch specification.")

        # Step 3: Set some defaults and set the public and private properties
        if not default_analysis_mode:
            default_analysis_mode = 'symbolic'
        if not ignore_functions:
            ignore_functions = []

        if isinstance(exclude_sim_procedures_func, types.LambdaType):
            l.warning("Passing a lambda type as the exclude_sim_procedures_func argument to Project causes the resulting object to be un-serializable.")

        self._sim_procedures = {}
        self._default_analysis_mode = default_analysis_mode
        self._exclude_sim_procedures_func = exclude_sim_procedures_func
        self._exclude_sim_procedures_list = exclude_sim_procedures_list
        self._should_use_sim_procedures = use_sim_procedures
        self._parallel = parallel
        self._support_selfmodifying_code = support_selfmodifying_code
        self._ignore_functions = ignore_functions
        self._extern_obj = AngrExternObject()
        self.loader.add_object(self._extern_obj)

        self._cfg = None
        self._vfg = None
        self._cdg = None

        self.entry = self.loader.main_bin.entry
        self.factory = AngrObjectFactory(self)
        self.analyses = Analyses(self)
        self.surveyors = Surveyors(self)

        projects[self.filename] = self

        # Step 4: Register simprocedures as appropriate for library functions
        self._use_sim_procedures()

        # Step 5: determine the host OS and perform additional initialization
        # in the SimOS constructor
        if isinstance(simos, type) and issubclass(simos, SimOS):
            self._simos = simos(self) #pylint:disable=invalid-name
        elif simos is None:
            self._simos = os_mapping[self.loader.main_bin.os](self)
        else:
            raise ValueError("Invalid OS specification or non-matching architecture.")

    #
    # Public methods
    #

    def hook(self, addr, func, length=0, kwargs=None):
        """
         Hook a section of code with a custom function.

         @param addr        The address to hook
         @param func        A python function or SimProcedure class that will perform an action when
                            execution reaches the hooked address
         @param length      How many bytes you'd like to skip over with your hook. Can be zero.
         @param kwargs      A dictionary of keyword arguments to be passed to your function or
                            your SimProcedure's run function.

         If func is a function, it takes a SimState and the given kwargs. It can return nothing
         (None), in which case it will generate a single exit to the instruction at addr+length,
         or it can return an array of successor states.

         If func is a SimProcedure, it will be run instead of a SimBlock at that address.

         If length is zero, the block at the hooked address will be executed immediately
         after the hook function.
        """

        if self.is_hooked(addr):
            l.warning("Address is already hooked [hook(%#x, %s)]", addr, func)
            return

        if kwargs is None: kwargs = {}

        if isinstance(func, type):
            proc = func
        elif hasattr(func, '__call__'):
            proc = simuvex.procedures.stubs.UserHook.UserHook
            kwargs = {'user_func': func, 'user_kwargs': kwargs, 'default_return_addr': addr+length}
        else:
            raise AngrError("%s is not a valid object to execute in a hook", func)

        self._sim_procedures[addr] = (proc, kwargs)

    def is_hooked(self, addr):
        return addr in self._sim_procedures

    def unhook(self, addr):
        if not self.is_hooked(addr):
            l.warning("Address %#x not hooked", addr)
            return

        del self._sim_procedures[addr]

    #
    # Pickling
    #

    def __getstate__(self):
        try:
            factory, analyses, surveyors = self.factory, self.analyses, self.surveyors
            self.factory, self.analyses, self.surveyors = None, None, None
            return dict(self.__dict__)
        finally:
            self.factory, self.analyses, self.surveyors = factory, analyses, surveyors

    def __setstate__(self, s):
        self.__dict__.update(s)
        self.factory = AngrObjectFactory(self)
        self.analyses = Analyses(self)
        self.surveyors = Surveyors(self)

    #
    # Private project stuff for simprocedures
    #

    def _should_exclude_sim_procedure(self, f):
        return (f in self._exclude_sim_procedures_list) or \
               ( self._exclude_sim_procedures_func is not None and \
                 self._exclude_sim_procedures_func(f)
               )

    def _find_sim_libraries(self):
        """ Look for libaries that we can replace with their simuvex
        simprocedures counterpart
        This function returns the list of libraries that were found in simuvex
        """
        simlibs = []

        for lib_name in self.loader.requested_objects:
            # Hack that should go somewhere else:
            if lib_name == 'libc.so.0':
                lib_name = 'libc.so.6'

            if lib_name == 'ld-uClibc.so.0':
                lib_name = 'ld-uClibc.so.6'

            if lib_name not in simuvex.procedures.SimProcedures:
                l.debug("There are no simprocedures for library %s :(", lib_name)
            else:
                simlibs.append(lib_name)

        return simlibs

    def _use_sim_procedures(self):
        """ Use simprocedures where we can """
        libs = self._find_sim_libraries()
        for obj in self.loader.all_objects:
            unresolved = []
            for reloc in obj.imports.itervalues():
                func = reloc.symbol
                if not func.is_function:
                    continue
                elif func.name in self._ignore_functions:
                    unresolved.append(func)
                    continue
                elif self._should_exclude_sim_procedure(func.name):
                    continue

                elif self._should_use_sim_procedures:
                    for lib in libs:
                        simfun = simuvex.procedures.SimProcedures[lib]
                        if func.name in simfun:
                            l.info("[R] %s:", func.name)
                            l.debug("\t -> matching SimProcedure in %s :)", lib)
                            self.set_sim_procedure(obj, func.name, simfun[func.name], None)
                            break
                    else: # we could not find a simprocedure for this function
                        if not func.resolved:   # the loader couldn't find one either
                            unresolved.append(func)
                # in the case that simprocedures are off and an object in the PLT goes
                # unresolved, we still want to replace it with a retunconstrained.
                elif not func.resolved and func.name in obj.jmprel:
                    unresolved.append(func)

            for func in unresolved:
                # Don't touch weakly bound symbols, they are allowed to go unresolved
                if func.is_weak:
                    continue
                l.info("[U] %s", func.name)
                procedure = simuvex.SimProcedures['stubs']['NoReturnUnconstrained']
                if func.name not in procedure.use_cases:
                    procedure = simuvex.SimProcedures['stubs']['ReturnUnconstrained']
                self.set_sim_procedure(obj, func.name, procedure, {'resolves': func.name})

    def set_sim_procedure(self, binary, func_name, sim_proc, kwargs=None):
        """
         Use a simprocedure to resolve a dependency in a binary.

         @param binary      The CLE binary whose dependency is to be resolve
         @param func_name   The name of the dependency to resolve
         @param sim_proc    The class of the SimProcedure to use
         @param kwargs      An optional dictionary of arguments to be passed
                            to the simprocedure's run() method.
        """
        if kwargs is None: kwargs = {}
        ident = sim_proc.__module__ + '.' + sim_proc.__name__
        if 'resolves' in kwargs:
            ident += '.' + kwargs['resolves']
        pseudo_addr = self._extern_obj.get_pseudo_addr(ident)
        binary.set_got_entry(func_name, pseudo_addr)

        if not self.is_hooked(pseudo_addr):     # Do not add duplicate simprocedures
            self.hook(pseudo_addr, sim_proc, kwargs=kwargs)
            l.debug("\t -> setting SimProcedure with pseudo_addr 0x%x...", pseudo_addr)

from .errors import AngrError
from .factory import AngrObjectFactory
from .simos import SimOS, os_mapping
from .extern_obj import AngrExternObject
from .analysis import Analyses
from .surveyor import Surveyors
<|endoftext|>


<commit_before>#!/usr/bin/env python
#
# Copyright (c) 2012, 2013 Robert Martens <robert.martens@gmail.com>
# See file COPYING.txt for MIT license terms.

"""
Find floating point vertex coordinates in a Source engine .vmf file.

Looks through a .vmf for any brush planes whose vertices have
non-integer coordinates, printing a list to stdout and optionally
writing out a new file with rounded values. As a side effect of its
brute force regex search, vertalert only checks enabled VisGroups.

"""

import decimal as dec
import os
import re
import sys

def get_dev(coord, snap):
    """
    Compute a coordinate's deviation from the nearest multiple of snap.

    Keyword arguments:
        coord: the coordinate to check
        snap: base value from which to compute deviation

    """
    orig = dec.Decimal(coord)
    rounded = (orig / snap).quantize(1, dec.ROUND_HALF_EVEN) * snap
    return abs(rounded - orig)

def get_max_dev(planes, snap):
    """
    Search a brush's planes for the largest deviation any one of its
    vertices' coordinates makes from the nearest multiple of snap.

    Keyword arguments:
        planes: list of strings representing the planes to check
        snap: base value from which to compute deviation

    """
    floats = []
    for plane in planes:
        # We're only looking for coordinates that were written to the
        # VMF as floating point values, perhaps in scientific notation.
        floats += re.findall(r'-?\d+\.\d+e?-?\d*', plane)
    devs = []
    for coord in floats:
        devs.append(get_dev(coord, snap))

    return max(devs)

def fix_plane(plane, thresh, snaplo, snaphi):
    """
    Find floating point coordinates in a plane, round to nearest multiple of
    snaplo or snaphi depending on computed deviation, and return corrected plane
    string.

    Keyword arguments:
        plane: string to search for floats
        thresh: threshold between snaplo and snaphi
        snaplo: deviations less than thresh will be rounded to the nearest
                multiple of this value
        snaphi: deviations equal to or greater than thresh will be rounded to
                the nearest multiple of this value

    """
    floats = re.findall(r'-?\d+\.\d+e?-?\d*', plane)
    plane_new = plane
    for coord in floats:
        orig = dec.Decimal(coord)
        if get_dev(orig, snaplo) < thresh:
            rounded = (orig / snaplo).quantize(1, dec.ROUND_HALF_EVEN) * snaplo
        elif snaphi is not None:
            rounded = (orig / snaphi).quantize(1, dec.ROUND_HALF_EVEN) * snaphi

        # I want to remove trailing zeroes from the rounded results, and the
        # normalize method does that. Normalizing all values, however, will
        # introduce scientific notation for integers that end in a zero, so I
        # only modify values containing a decimal point. This is only cosmetic.
        if '.' in str(rounded):
            rounded = rounded.normalize()

        # I replace str(coord) instead of orig here, since
        # that would miss values using scientific notation.
        plane_new = plane_new.replace(str(coord), str(rounded), 1)

    return plane_new

def fix_brushes(brushes, thresh, vmf_in, snaplo, snaphi):
    """
    Find and fix brushes with floating point plane coordinates.

    Returns a tuple containing the total number of brushes whose coordinates
    were rounded, a list of tuples which pairs suspicious brush IDs with the
    greatest deviation any one of their coordinates makes from the nearest
    multiple of snaplo, and a fixed version of vmf_in.

    Keyword arguments:
        brushes: list of brush strings to search
        thresh: threshold between snaplo and snaphi
        vmf_in: string containing input VMF contents
        snaplo: deviations less than thresh will be rounded to the nearest
                multiple of this value
        snaphi: deviations equal to or greater than thresh will be rounded to
                the nearest multiple of this value

    """
    vmf_out = vmf_in
    rounded_count = 0
    percent = len(brushes) / 100.0
    suspects = []
    for i, brush in enumerate(brushes):
        brush_id = int(re.search(r'"id"\s"(\d+)"', brush).group(1))
        float_planes = []
        for plane in re.findall(r'"plane"\s".*?"', brush, re.DOTALL):
            if '.' in plane:
                float_planes.append(plane)
        if not float_planes:
            continue

        max_dev = get_max_dev(float_planes, snaplo)
        if max_dev < thresh or snaphi is not None:
            brush_new = brush
            for plane in float_planes:
                plane_new = fix_plane(plane, thresh, snaplo, snaphi)
                brush_new = brush_new.replace(plane, plane_new)
            vmf_out = vmf_out.replace(brush, brush_new)
            rounded_count += 1
        else:
            suspects.append((brush_id, max_dev))

        sys.stdout.write('\r%s%% complete' % str(int(i / percent)))
        sys.stdout.flush()
    sys.stdout.write("\r             \n")
    sys.stdout.flush()

    return (rounded_count, suspects, vmf_out)

def print_dev_table(suspects, rounded_count, fix):
    """
    Print, to stdout, a table displaying each brush ID and its
    coordinates' maximum deviation from the nearest multiple of snaplo.

    Keyword arguments:
        suspects: a list of tuples pairing brush id with max deviation
        rounded_count: the number of brushes whose coordinates were rounded
        fix: whether or not a modified VMF is being written to disk

    """
    if suspects:
        suspects = sorted(suspects, key=lambda suspect: suspect[-1])
        max_id_width = len(str(max(suspects[0])))
        left_w = max(max_id_width, len("Suspect ID"))
        header = ("Suspect ID").rjust(left_w) + '  ' + "Max dev" + '\n'
        sys.stdout.write(header)
        sys.stdout.write('-' * (len(header) - 1) + '\n')
        for suspect in suspects:
            left = str(suspect[0]).rjust(left_w)
            right = str(suspect[1])
            sys.stdout.write(left + "  " + right + "\n")
            sys.stdout.flush()
        sys.stdout.write('\n')

    if len(suspects) == 1:
        warn_suffix = ""
    else:
        warn_suffix = "es"
    if rounded_count == 1:
        action_suffix = ""
    else:
        action_suffix = "es"
    if fix:
        action = " automatically rounded"
    else:
        action = " ignored"

    sys.stdout.write(str(rounded_count) + " brush" +
                     action_suffix + action + '\n')
    sys.stdout.write(str(len(suspects)) + " suspect brush" +
                     warn_suffix + " remaining\n")
    sys.stdout.flush()

def vertalert(file_in, fix=False, fixname=None, thresh=None,
              snaplo=None, snaphi=None):
    """
    Find, display, and optionally round floating point plane coordinates in a
    Source engine .vmf file.

    Keyword arguments:
        file_in: .vmf file to check
        fix: write out a new file with rounded coordinates (default False)
        fixname: filename when using --fix (default appends _VERTALERT)
        thresh: threshold between snaplo and snaphi (default snaplo * 0.2)
        snaplo: deviations less than thresh will be rounded to the nearest
                multiple of this value (default 1)
        snaphi: deviations equal to or greater than thresh will be rounded to
                the nearest multiple of this value (default None)

    Please note this function currently only checks enabled VisGroups.

    """
    if not os.path.exists(file_in):
        sys.stderr.write("Could not find " + file_in + "!\n")
        return -1
    if os.path.splitext(file_in)[1] != ".vmf":
        sys.stderr.write("Input must be a .vmf file!\n")
        return -1
    if fixname is None:
        in_name_split = os.path.splitext(file_in)
        fixname = in_name_split[0] + "_VERTALERT" + in_name_split[1]
    if snaplo is None:
        snaplo = dec.Decimal('1')
    if thresh is None:
        thresh = snaplo * dec.Decimal('0.2')

    with open(file_in, 'r') as vmf:
        vmf_in = vmf.read()

    # I no longer read the input in universal line ending mode above,
    # as that changes the type of line endings written to the output
    # when using --fix. Although Hammer can deal with at least Windows
    # and Unix endings, I prefer to write out the same thing I read in.
    # The \r?\n in this regular expression became necessary to ensure
    # Windows, Linux and OS X worked the same way. The pattern is that
    # of the beginning of a solid entry, whose VisGroup is enabled, and
    # breaks down as follows:
    #
    # solid - The word 'solid'.
    # \r?\n - Zero or one carriage return followed by one newline. In
    #         Windows, \n is what \r\n is under Linux and OS X.
    # \t{ - Tab, open curly brace
    # .*? - Zero or more of any character (including newlines, thanks
    #       to my use of re.DOTALL in the call to findall), non-greedy.
    # \r?\n\t} - Zero or one carriage return, one newline, one tab,
    #            closing curly brace.
    brushes = re.findall(r'solid\r?\n\t{.*?\r?\n\t}', vmf_in, re.DOTALL)
    rounded_count, suspects, vmf_out = fix_brushes(brushes, thresh, vmf_in,
                                               snaplo, snaphi)

    print_dev_table(suspects, rounded_count, fix)

    if fix:
        with open(fixname, 'w') as vmf:
            vmf.write(vmf_out)
        sys.stdout.write("\nWrote " + fixname + "!\n")
        sys.stdout.flush()

    return 0

if __name__ == '__main__':
    import argparse
    PARSER = argparse.ArgumentParser(description="VertAlert 0.2.1")
    PARSER.add_argument("input", help="VMF to check")
    PARSER.add_argument(
        "-f", "--fix", help="write fixed up VMF", action="store_true")
    PARSER.add_argument(
        "-fn", "--fixname",
        help="filename to use with --fix (default appends _VERTALERT)")
    PARSER.add_argument(
        "-t", "--thresh",
        type=dec.Decimal,
        help="threshold below which to ignore/round coordinates "
             "(default snaplo * 0.2)")
    PARSER.add_argument(
        "-sl", "--snaplo",
        type=dec.Decimal,
        help="coordinates with deviations less than thresh will be rounded to "
             "the nearest multiple of this value (default 1)")
    PARSER.add_argument(
        "-sh", "--snaphi",
        type=dec.Decimal,
        help="coordinates with deviations equal to or greater than thresh will "
             "be rounded to the nearest multiple of this value (default None)")
    ARGS = PARSER.parse_args()

    vertalert(ARGS.input, ARGS.fix, ARGS.fixname, ARGS.thresh,
              ARGS.snaplo, ARGS.snaphi)
<commit_msg>Adjust whitespace<commit_after>#!/usr/bin/env python
#
# Copyright (c) 2012, 2013 Robert Martens <robert.martens@gmail.com>
# See file COPYING.txt for MIT license terms.

"""
Find floating point vertex coordinates in a Source engine .vmf file.

Looks through a .vmf for any brush planes whose vertices have
non-integer coordinates, printing a list to stdout and optionally
writing out a new file with rounded values. As a side effect of its
brute force regex search, vertalert only checks enabled VisGroups.

"""

import decimal as dec
import os
import re
import sys

def get_dev(coord, snap):
    """
    Compute a coordinate's deviation from the nearest multiple of snap.

    Keyword arguments:
        coord: the coordinate to check
        snap: base value from which to compute deviation

    """
    orig = dec.Decimal(coord)
    rounded = (orig / snap).quantize(1, dec.ROUND_HALF_EVEN) * snap
    return abs(rounded - orig)

def get_max_dev(planes, snap):
    """
    Search a brush's planes for the largest deviation any one of its
    vertices' coordinates makes from the nearest multiple of snap.

    Keyword arguments:
        planes: list of strings representing the planes to check
        snap: base value from which to compute deviation

    """
    floats = []
    for plane in planes:
        # We're only looking for coordinates that were written to the
        # VMF as floating point values, perhaps in scientific notation.
        floats += re.findall(r'-?\d+\.\d+e?-?\d*', plane)
    devs = []
    for coord in floats:
        devs.append(get_dev(coord, snap))
    return max(devs)

def fix_plane(plane, thresh, snaplo, snaphi):
    """
    Find floating point coordinates in a plane, round to nearest multiple of
    snaplo or snaphi depending on computed deviation, and return corrected plane
    string.

    Keyword arguments:
        plane: string to search for floats
        thresh: threshold between snaplo and snaphi
        snaplo: deviations less than thresh will be rounded to the nearest
                multiple of this value
        snaphi: deviations equal to or greater than thresh will be rounded to
                the nearest multiple of this value

    """
    floats = re.findall(r'-?\d+\.\d+e?-?\d*', plane)
    plane_new = plane
    for coord in floats:
        orig = dec.Decimal(coord)
        if get_dev(orig, snaplo) < thresh:
            rounded = (orig / snaplo).quantize(1, dec.ROUND_HALF_EVEN) * snaplo
        elif snaphi is not None:
            rounded = (orig / snaphi).quantize(1, dec.ROUND_HALF_EVEN) * snaphi

        # I want to remove trailing zeroes from the rounded results, and the
        # normalize method does that. Normalizing all values, however, will
        # introduce scientific notation for integers that end in a zero, so I
        # only modify values containing a decimal point. This is only cosmetic.
        if '.' in str(rounded):
            rounded = rounded.normalize()

        # I replace str(coord) instead of orig here, since
        # that would miss values using scientific notation.
        plane_new = plane_new.replace(str(coord), str(rounded), 1)

    return plane_new

def fix_brushes(brushes, thresh, vmf_in, snaplo, snaphi):
    """
    Find and fix brushes with floating point plane coordinates.

    Returns a tuple containing the total number of brushes whose coordinates
    were rounded, a list of tuples which pairs suspicious brush IDs with the
    greatest deviation any one of their coordinates makes from the nearest
    multiple of snaplo, and a fixed version of vmf_in.

    Keyword arguments:
        brushes: list of brush strings to search
        thresh: threshold between snaplo and snaphi
        vmf_in: string containing input VMF contents
        snaplo: deviations less than thresh will be rounded to the nearest
                multiple of this value
        snaphi: deviations equal to or greater than thresh will be rounded to
                the nearest multiple of this value

    """
    vmf_out = vmf_in
    rounded_count = 0
    percent = len(brushes) / 100.0
    suspects = []
    for i, brush in enumerate(brushes):
        brush_id = int(re.search(r'"id"\s"(\d+)"', brush).group(1))
        float_planes = []
        for plane in re.findall(r'"plane"\s".*?"', brush, re.DOTALL):
            if '.' in plane:
                float_planes.append(plane)
        if not float_planes:
            continue

        max_dev = get_max_dev(float_planes, snaplo)
        if max_dev < thresh or snaphi is not None:
            brush_new = brush
            for plane in float_planes:
                plane_new = fix_plane(plane, thresh, snaplo, snaphi)
                brush_new = brush_new.replace(plane, plane_new)
            vmf_out = vmf_out.replace(brush, brush_new)
            rounded_count += 1
        else:
            suspects.append((brush_id, max_dev))

        sys.stdout.write('\r%s%% complete' % str(int(i / percent)))
        sys.stdout.flush()

    sys.stdout.write("\r             \n")
    sys.stdout.flush()

    return (rounded_count, suspects, vmf_out)

def print_dev_table(suspects, rounded_count, fix):
    """
    Print, to stdout, a table displaying each brush ID and its
    coordinates' maximum deviation from the nearest multiple of snaplo.

    Keyword arguments:
        suspects: a list of tuples pairing brush id with max deviation
        rounded_count: the number of brushes whose coordinates were rounded
        fix: whether or not a modified VMF is being written to disk

    """
    if suspects:
        suspects = sorted(suspects, key=lambda suspect: suspect[-1])
        max_id_width = len(str(max(suspects[0])))
        left_w = max(max_id_width, len("Suspect ID"))
        header = ("Suspect ID").rjust(left_w) + '  ' + "Max dev" + '\n'
        sys.stdout.write(header)
        sys.stdout.write('-' * (len(header) - 1) + '\n')
        for suspect in suspects:
            left = str(suspect[0]).rjust(left_w)
            right = str(suspect[1])
            sys.stdout.write(left + "  " + right + "\n")
            sys.stdout.flush()
        sys.stdout.write('\n')

    if len(suspects) == 1:
        warn_suffix = ""
    else:
        warn_suffix = "es"
    if rounded_count == 1:
        action_suffix = ""
    else:
        action_suffix = "es"
    if fix:
        action = " automatically rounded"
    else:
        action = " ignored"

    sys.stdout.write(str(rounded_count) + " brush" +
                     action_suffix + action + '\n')
    sys.stdout.write(str(len(suspects)) + " suspect brush" +
                     warn_suffix + " remaining\n")
    sys.stdout.flush()

def vertalert(file_in, fix=False, fixname=None, thresh=None,
              snaplo=None, snaphi=None):
    """
    Find, display, and optionally round floating point plane coordinates in a
    Source engine .vmf file.

    Keyword arguments:
        file_in: .vmf file to check
        fix: write out a new file with rounded coordinates (default False)
        fixname: filename when using --fix (default appends _VERTALERT)
        thresh: threshold between snaplo and snaphi (default snaplo * 0.2)
        snaplo: deviations less than thresh will be rounded to the nearest
                multiple of this value (default 1)
        snaphi: deviations equal to or greater than thresh will be rounded to
                the nearest multiple of this value (default None)

    Please note this function currently only checks enabled VisGroups.

    """
    if not os.path.exists(file_in):
        sys.stderr.write("Could not find " + file_in + "!\n")
        return -1
    if os.path.splitext(file_in)[1] != ".vmf":
        sys.stderr.write("Input must be a .vmf file!\n")
        return -1
    if fixname is None:
        in_name_split = os.path.splitext(file_in)
        fixname = in_name_split[0] + "_VERTALERT" + in_name_split[1]
    if snaplo is None:
        snaplo = dec.Decimal('1')
    if thresh is None:
        thresh = snaplo * dec.Decimal('0.2')

    with open(file_in, 'r') as vmf:
        vmf_in = vmf.read()

    # I no longer read the input in universal line ending mode above,
    # as that changes the type of line endings written to the output
    # when using --fix. Although Hammer can deal with at least Windows
    # and Unix endings, I prefer to write out the same thing I read in.
    # The \r?\n in this regular expression became necessary to ensure
    # Windows, Linux and OS X worked the same way. The pattern is that
    # of the beginning of a solid entry, whose VisGroup is enabled, and
    # breaks down as follows:
    #
    # solid - The word 'solid'.
    # \r?\n - Zero or one carriage return followed by one newline. In
    #         Windows, \n is what \r\n is under Linux and OS X.
    # \t{ - Tab, open curly brace
    # .*? - Zero or more of any character (including newlines, thanks
    #       to my use of re.DOTALL in the call to findall), non-greedy.
    # \r?\n\t} - Zero or one carriage return, one newline, one tab,
    #            closing curly brace.
    brushes = re.findall(r'solid\r?\n\t{.*?\r?\n\t}', vmf_in, re.DOTALL)
    rounded_count, suspects, vmf_out = fix_brushes(brushes, thresh, vmf_in,
                                                   snaplo, snaphi)

    print_dev_table(suspects, rounded_count, fix)

    if fix:
        with open(fixname, 'w') as vmf:
            vmf.write(vmf_out)
        sys.stdout.write("\nWrote " + fixname + "!\n")
        sys.stdout.flush()

    return 0

if __name__ == '__main__':
    import argparse
    PARSER = argparse.ArgumentParser(description="VertAlert 0.2.1")
    PARSER.add_argument("input", help="VMF to check")
    PARSER.add_argument(
        "-f", "--fix", help="write fixed up VMF", action="store_true")
    PARSER.add_argument(
        "-fn", "--fixname",
        help="filename to use with --fix (default appends _VERTALERT)")
    PARSER.add_argument(
        "-t", "--thresh",
        type=dec.Decimal,
        help="threshold below which to ignore/round coordinates "
             "(default snaplo * 0.2)")
    PARSER.add_argument(
        "-sl", "--snaplo",
        type=dec.Decimal,
        help="coordinates with deviations less than thresh will be rounded to "
             "the nearest multiple of this value (default 1)")
    PARSER.add_argument(
        "-sh", "--snaphi",
        type=dec.Decimal,
        help="coordinates with deviations equal to or greater than thresh will "
             "be rounded to the nearest multiple of this value (default None)")
    ARGS = PARSER.parse_args()

    vertalert(ARGS.input, ARGS.fix, ARGS.fixname, ARGS.thresh,
              ARGS.snaplo, ARGS.snaphi)
<|endoftext|>


<commit_before>"""Absolute Value."""

def abs_val(num):
    """
    Find the absolute value of a number.

    >>abs_val(-5)
    5
    >>abs_val(0)
    0
    """
    if num < 0:
        return -num

    # Returns if number is not < 0
    return num

def main():
    """Print absolute value of -34."""
    print(abs_val(-34))  # = 34

if __name__ == "__main__":
    main()
<commit_msg>less code (#1292)<commit_after>"""Absolute Value."""

def abs_val(num):
    """
    Find the absolute value of a number.

    >>abs_val(-5)
    5
    >>abs_val(0)
    0
    """
    return -num if num < 0 else num

def main():
    """Print absolute value of -34."""
    print(abs_val(-34))  # = 34

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


<commit_before># Some pretty-printing routines to help dealing with angr objects

import angr
import claripy
import simuvex
from expr import *

def pp(obj, **kwargs):
    if isinstance(obj, angr.path_group.PathGroup):
        return pathgroup(obj, **kwargs)
    elif isinstance(obj, angr.path.Path):
        return path(obj, **kwargs)
    elif isinstance(obj, claripy.ast.base.Base):
        return ast(obj, **kwargs)
    elif isinstance(obj, simuvex.s_state.SimState):
        return state(obj, **kwargs)
    elif isinstance(obj, simuvex.s_action.SimAction):
        return action(obj, **kwargs)
    else:
        raise TypeError(type(obj))

def addr_trace(arr, delimiter=",", cols=10, fmtwidth=8, level=0):
    ret = ""
    for i in range(len(arr)):
        if i % cols == 0:
            ret += "\t"*level
        ret += ("0x%%0%dx" % fmtwidth) % arr[i]
        if i != len(arr)-1:
            ret += delimiter
        if i % cols == (cols-1) or i == len(arr)-1:
            ret += "\n"
    return ret

def path(p, delimiter=" -> ", cols=10, fmtwidth=8, level=0):
    ret = "\t"*level + "path '%s':\n" % p.path_id
    trace = p.addr_trace.hardcopy
    trace.append(p.addr)
    ret += addr_trace(trace, delimiter=delimiter, level=level+1, cols=cols, fmtwidth=fmtwidth)
    return ret

def pathgroup(pg, delimiter=" -> ", cols=10, fmtwidth=8, level=0):
    ret = "\t" * level + "pathgroups\n"
    for sname, stash in pg.stashes.iteritems():
        if len(stash) > 0:
            ret += ("\t" * (level+1) + "%s %d\n") % (sname,len(stash))
            for p in stash:
                ret += path(p, delimiter=delimiter, level=level+2, cols=cols, fmtwidth=fmtwidth)
    return ret

def ast(obj, level=0, last=True):
    ret = ""
    if hasattr(obj, 'op'):
        ret += "\t"*level + obj.op +"("
        if any([hasattr(arg, 'op') for arg in obj.args]):
            ret += "\n"
            for argidx in range(len(obj.args)):
                arg = obj.args[argidx]
                ret += ast(arg, level=level+1, last=argidx==len(obj.args)-1)
            ret += "\t"*level + ")" + ("," if not last else "") +"\n"
        else:
            ret += ",".join(map(str,obj.args)) + ")" + ("," if not last else "") + "\n"
    else:
        ret += "\t"*level + str(obj) + ("," if not last else "") + "\n"
    return ret

def _regname(regidx, arch=None):
    return arch.register_names[regidx] if arch else 'reg_'+str(regidx)

def _ao(obj, level=0, arch=None):
    s = "\t"*level
    if obj is not None:
        s +=  str(obj.ast)
        if len(obj.tmp_deps) > 0:
            s +=  " " + str(map(lambda x: "t%d" % x, obj.tmp_deps))
        if len(obj.reg_deps) > 0:
            s +=  " " + str(map(lambda x: _regname(x, arch), obj.reg_deps))
    return s

def action(obj, level=0, arch=None):
    if obj.sim_procedure is not None:
        location = "%s()" % obj.sim_procedure
    else:
        if obj.stmt_idx is not None:
            location = "0x%x:%d" % (obj.bbl_addr, obj.stmt_idx)
        else:
            location = "0x%x" % obj.bbl_addr

    s = "\t"*level + location + "\t"
    if obj.type == 'operation':
        tmpit = iter(obj.tmp_deps)
        exprit = iter(obj.exprs)
        s += "operation\t%s" % (obj.op)
        for expr in exprit:
            s += "\te:["+str(expr.ast)
            try:
                s += "[t" + str(next(tmpit)) + "]"
            except StopIteration:
                pass
            s += "] "
    elif obj.type == 'exit':
        s += obj.type
        s += "/" + obj.exit_type + " "
        s += "target:" + _ao(obj.target, arch=arch) + " "
        s += "cond:" + _ao(obj.condition, arch=arch)

    elif obj.type == 'constraint':
        s += obj.type
        s += "cons:" + _ao(obj.constraint, arch=arch) + " "
        s += "cond:" + _ao(obj.condition, arch=arch)
    else: #SimActionData
        s += obj.type
        s += "/%s(%s) " % ('r' if obj.action == 'read' else 'w', _ao(obj.size, arch=arch))
        if obj.type == 'reg':
            s += _regname(obj.addr.ast,arch)
        elif obj.type == 'tmp':
            s += str("t%d"%obj.tmp)
        else:
            s += "\ta:[" + _ao(obj.addr, arch=arch) + "]"

        s += "\td:[" + _ao(obj.data, arch=arch) + "]"
        if len(obj._tmp_dep) > 0:
            s +=  " _tmp_dep: " + str(map(lambda x: "t%d" % x, obj._tmp_dep))
        if len(obj._reg_dep) > 0:
            s +=  " _reg_dep: " + str(map(lambda x: _regname(x, arch), obj._reg_dep))
    return s

def _mem(se, reg):
    if reg.concrete:
        return "%08x" % reg.args[0]
    elif reg.symbolic:
        l,u = get_signed_range(se, reg)
        l = abs(l)
        if len(reg.args) == 1 and reg.args[0].op == 'BVS':
            return "%08x..%08x" % (l,u) + " ; " + str(reg.args[0].args[0])
        else:
            return "%08x..%08x" % (l,u) + " ; DEP: " + str(list(reg.variables))
    else:
        return "UNKNOWN " + type(reg)

def state(state, level=0, regs=True, stack=True, stackrange=[0,32], header=True):
    ret = ""
    if regs:
        if header:
            ret += "\t"*level + "====== Registers ======\n"
        ret += "\t"*level + "EAX: %s\n" % _mem(state.se, state.regs.eax)
        ret += "\t"*level + "EBX: %s\n" % _mem(state.se, state.regs.ebx)
        ret += "\t"*level + "ECX: %s\n" % _mem(state.se, state.regs.ecx)
        ret += "\t"*level + "EDX: %s\n" % _mem(state.se, state.regs.edx)
        ret += "\t"*level + "ESI: %s\n" % _mem(state.se, state.regs.esi)
        ret += "\t"*level + "EDI: %s\n" % _mem(state.se, state.regs.edi)
        ret += "\t"*level + "EBP: %s\n" % _mem(state.se, state.regs.ebp)
        ret += "\t"*level + "ESP: %s\n" % _mem(state.se, state.regs.esp)
        ret += "\t"*level + "EIP: %s\n" % _mem(state.se, state.regs.eip)
    if stack:
        if header:
            ret += "\t"*level + "======== Stack ========\n"
        ba = state.regs.esp.args[0]
        for i in range(stackrange[0],stackrange[1],4):
            ret += "\t"*level + "%+03x: %08x %s\n" % (i, ba+i, _mem(state.se, state.memory.load(ba+i, inspect=False)))
    return ret

<commit_msg>Add annotations to expression pretty-printer<commit_after># Some pretty-printing routines to help dealing with angr objects

import angr
import claripy
import simuvex
from expr import *

def pp(obj, **kwargs):
    if isinstance(obj, angr.path_group.PathGroup):
        return pathgroup(obj, **kwargs)
    elif isinstance(obj, angr.path.Path):
        return path(obj, **kwargs)
    elif isinstance(obj, claripy.ast.base.Base):
        return ast(obj, **kwargs)
    elif isinstance(obj, simuvex.s_state.SimState):
        return state(obj, **kwargs)
    elif isinstance(obj, simuvex.s_action.SimAction):
        return action(obj, **kwargs)
    else:
        raise TypeError(type(obj))

def addr_trace(arr, delimiter=",", cols=10, fmtwidth=8, level=0):
    ret = ""
    for i in range(len(arr)):
        if i % cols == 0:
            ret += "\t"*level
        ret += ("0x%%0%dx" % fmtwidth) % arr[i]
        if i != len(arr)-1:
            ret += delimiter
        if i % cols == (cols-1) or i == len(arr)-1:
            ret += "\n"
    return ret

def path(p, delimiter=" -> ", cols=10, fmtwidth=8, level=0):
    ret = "\t"*level + "path '%s':\n" % p.path_id
    trace = p.addr_trace.hardcopy
    trace.append(p.addr)
    ret += addr_trace(trace, delimiter=delimiter, level=level+1, cols=cols, fmtwidth=fmtwidth)
    return ret

def pathgroup(pg, delimiter=" -> ", cols=10, fmtwidth=8, level=0):
    ret = "\t" * level + "pathgroups\n"
    for sname, stash in pg.stashes.iteritems():
        if len(stash) > 0:
            ret += ("\t" * (level+1) + "%s %d\n") % (sname,len(stash))
            for p in stash:
                ret += path(p, delimiter=delimiter, level=level+2, cols=cols, fmtwidth=fmtwidth)
    return ret

def ast(obj, level=0, last=True, annotations=False):
    def _to_str(annotations):
        return " ".join(map(str, annotations))

    ret = ""
    if hasattr(obj, 'op'):
        ret += "\t"*level + obj.op +"("
        if any([hasattr(arg, 'op') for arg in obj.args]):
            ret += "\n"
            for argidx in range(len(obj.args)):
                arg = obj.args[argidx]
                ret += ast(arg, level=level+1, last=argidx==len(obj.args)-1, annotations=annotations)
            ret += "\t"*level + ")"
        else:
            ret += ",".join(map(str,obj.args)) + ")"
        if annotations and hasattr(obj, 'annotations') and len(obj.annotations)>0:
            ret += " [" + _to_str(obj.annotations) + "]"
        ret += ("," if not last else "") + "\n"
    else:
        ret += "\t"*level + str(obj) + ("," if not last else "") + "\n"
    return ret

def _regname(regidx, arch=None):
    return arch.register_names[regidx] if arch else 'reg_'+str(regidx)

def _ao(obj, level=0, arch=None):
    s = "\t"*level
    if obj is not None:
        s +=  str(obj.ast)
        if len(obj.tmp_deps) > 0:
            s +=  " " + str(map(lambda x: "t%d" % x, obj.tmp_deps))
        if len(obj.reg_deps) > 0:
            s +=  " " + str(map(lambda x: _regname(x, arch), obj.reg_deps))
    return s

def action(obj, level=0, arch=None):
    if obj.sim_procedure is not None:
        location = "%s()" % obj.sim_procedure
    else:
        if obj.stmt_idx is not None:
            location = "0x%x:%d" % (obj.bbl_addr, obj.stmt_idx)
        else:
            location = "0x%x" % obj.bbl_addr

    s = "\t"*level + location + "\t"
    if obj.type == 'operation':
        tmpit = iter(obj.tmp_deps)
        exprit = iter(obj.exprs)
        s += "operation\t%s" % (obj.op)
        for expr in exprit:
            s += "\te:["+str(expr.ast)
            try:
                s += "[t" + str(next(tmpit)) + "]"
            except StopIteration:
                pass
            s += "] "
    elif obj.type == 'exit':
        s += obj.type
        s += "/" + obj.exit_type + " "
        s += "target:" + _ao(obj.target, arch=arch) + " "
        s += "cond:" + _ao(obj.condition, arch=arch)

    elif obj.type == 'constraint':
        s += obj.type
        s += "cons:" + _ao(obj.constraint, arch=arch) + " "
        s += "cond:" + _ao(obj.condition, arch=arch)
    else: #SimActionData
        s += obj.type
        s += "/%s(%s) " % ('r' if obj.action == 'read' else 'w', _ao(obj.size, arch=arch))
        if obj.type == 'reg':
            s += _regname(obj.addr.ast,arch)
        elif obj.type == 'tmp':
            s += str("t%d"%obj.tmp)
        else:
            s += "\ta:[" + _ao(obj.addr, arch=arch) + "]"

        s += "\td:[" + _ao(obj.data, arch=arch) + "]"
        if len(obj._tmp_dep) > 0:
            s +=  " _tmp_dep: " + str(map(lambda x: "t%d" % x, obj._tmp_dep))
        if len(obj._reg_dep) > 0:
            s +=  " _reg_dep: " + str(map(lambda x: _regname(x, arch), obj._reg_dep))
    return s

def _mem(se, reg):
    if reg.concrete:
        return "%08x" % reg.args[0]
    elif reg.symbolic:
        l,u = get_signed_range(se, reg)
        l = abs(l)
        if len(reg.args) == 1 and reg.args[0].op == 'BVS':
            return "%08x..%08x" % (l,u) + " ; " + str(reg.args[0].args[0])
        else:
            return "%08x..%08x" % (l,u) + " ; DEP: " + str(list(reg.variables))
    else:
        return "UNKNOWN " + type(reg)

def state(state, level=0, regs=True, stack=True, stackrange=[0,32], header=True):
    ret = ""
    if regs:
        if header:
            ret += "\t"*level + "====== Registers ======\n"
        ret += "\t"*level + "EAX: %s\n" % _mem(state.se, state.regs.eax)
        ret += "\t"*level + "EBX: %s\n" % _mem(state.se, state.regs.ebx)
        ret += "\t"*level + "ECX: %s\n" % _mem(state.se, state.regs.ecx)
        ret += "\t"*level + "EDX: %s\n" % _mem(state.se, state.regs.edx)
        ret += "\t"*level + "ESI: %s\n" % _mem(state.se, state.regs.esi)
        ret += "\t"*level + "EDI: %s\n" % _mem(state.se, state.regs.edi)
        ret += "\t"*level + "EBP: %s\n" % _mem(state.se, state.regs.ebp)
        ret += "\t"*level + "ESP: %s\n" % _mem(state.se, state.regs.esp)
        ret += "\t"*level + "EIP: %s\n" % _mem(state.se, state.regs.eip)
    if stack:
        if header:
            ret += "\t"*level + "======== Stack ========\n"
        ba = state.regs.esp.args[0]
        for i in range(stackrange[0],stackrange[1],4):
            ret += "\t"*level + "%+03x: %08x %s\n" % (i, ba+i, _mem(state.se, state.memory.load(ba+i, inspect=False)))
    return ret

<|endoftext|>


<commit_before>import tuio
import stomp

s = stomp.Connection()
s.start()
s.connect()

cnt = 0

current = []
ld = {}

t = tuio.Tracking()
try:
	while True:
		t.update()

		active = []
		for c in t.cursors():
			active.append(c.sessionid)

		tbr = []
		for c in current:
			if c not in active:
				tbr.append(c)

		tba = []
		for c in active:
			if c not in current:
				tba.append(c)

		current = active

		for c in tbr:
			d = ld[c]
			s.send("C R %d %f %f" % (c, d[1], d[2]), destination="/topic/home")
			ld.pop(c)

		# for c in tba:
		# 	s.send("C N %d" % c, destination="/topic/home")

		for c in t.cursors():
			data = (c.sessionid, c.xpos, c.ypos)
			if not ld.get(c.sessionid, None) == data:
				if c.sessionid in tba:
					msg = "C N %d %f %f" % data
				else:
					msg = "C U %d %f %f" % data
				s.send(msg, destination="/topic/home")
				ld[c.sessionid] = data
				cnt += 1
				print cnt
				print "[cursor] [%d] (%f, %f) (%f, %f) %f" % (c.sessionid, c.xpos, c.ypos, c.xmot, c.ymot, c.mot_accel)
except KeyboardInterrupt:
	t.stop()

<commit_msg>Add stomp producer. Currently only transmits events from fingers.<commit_after>import tuio
import stomp

s = stomp.Connection()
s.start()
s.connect()

cnt = 0

current = []
ld = {}

t = tuio.Tracking()
try:
	while True:
		t.update()

		active = []
		for c in t.cursors():
			active.append(c.sessionid)

		tbr = []
		for c in current:
			if c not in active:
				tbr.append(c)

		tba = []
		for c in active:
			if c not in current:
				tba.append(c)

		current = active

		for c in tbr:
			d = ld[c]
			# cursor removed = 5
			s.send("5 %d %d %f %f 0" % (c, c, d[1], d[2]), destination="/topic/home")
			ld.pop(c)

		# for c in tba:
		# 	s.send("C N %d" % c, destination="/topic/home")

		for c in t.cursors():
			data = (c.sessionid, c.sessionid, c.xpos, c.ypos)
			if not ld.get(c.sessionid, None) == data:
				if c.sessionid in tba:
					# cursor new = 3
					msg = "3 %d %d %f %f 0" % data
				else:
					# cursor update = 4
					msg = "4 %d %d %f %f 0" % data
				s.send(msg, destination="/topic/home")
				ld[c.sessionid] = data
				cnt += 1

except KeyboardInterrupt:
	t.stop()

<|endoftext|>