<commit_before>"""Unit test for Contiguity.py"""
import unittest
import pysal
import numpy as np

class TestContiguity(unittest.TestCase):
    def setUp(self):
        self.polyShp = '../../examples/10740.shp'

    def test_buildContiguity(self):
        w = buildContiguity(pysal.open(self.polyShp, 'r'))
        self.assertEqual(w[0],  {1: 1.0, 4: 1.0, 101: 1.0, 85: 1.0, 5: 1.0})
        w = buildContiguity(pysal.open(self.polyShp, 'r'), criterion='queen')
        self.assertEqual(w.pct_nonzero, 0.031926364234056544)
        w = buildContiguity(pysal.open(self.polyShp, 'r'), criterion='rook')
        self.assertEqual(w.pct_nonzero, 0.026351084812623275)
        fips = pysal.open('../../examples/10740.dbf').by_col('STFID')
        w = buildContiguity(pysal.open(self.polyShp, 'r'), ids = fips)
        self.assertEqual(w['35001000107'], {'35001003805': 1.0, '35001003721':
            1.0, '35001000111': 1.0, '35001000112': 1.0, '35001000108': 1.0})

if __name__ == "__main__":
    unittest.main()
<commit_msg>fixing unittest for namespace <commit_after>"""Unit test for Contiguity.py"""
import unittest
import pysal
import numpy as np

class TestContiguity(unittest.TestCase):
    def setUp(self):
        self.polyShp = '../../examples/10740.shp'

    def test_buildContiguity(self):
        w = pysal.buildContiguity(pysal.open(self.polyShp, 'r'))
        self.assertEqual(w[0],  {1: 1.0, 4: 1.0, 101: 1.0, 85: 1.0, 5: 1.0})
        w = pysal.buildContiguity(pysal.open(self.polyShp, 'r'), criterion='queen')
        self.assertEqual(w.pct_nonzero, 0.031926364234056544)
        w = pysal.buildContiguity(pysal.open(self.polyShp, 'r'), criterion='rook')
        self.assertEqual(w.pct_nonzero, 0.026351084812623275)
        fips = pysal.open('../../examples/10740.dbf').by_col('STFID')
        w = pysal.buildContiguity(pysal.open(self.polyShp, 'r'), ids = fips)
        self.assertEqual(w['35001000107'], {'35001003805': 1.0, '35001003721':
            1.0, '35001000111': 1.0, '35001000112': 1.0, '35001000108': 1.0})

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


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

from __future__ import division
import pandas as pd
import numpy as np

def list2pd(all_data, subjindex=None, listindex=None):
    """
    Makes multi-indexed dataframe of subject data

    Parameters
    ----------
    all_data : list of lists of strings
        strings are either all presented or all recalled items, in the order of presentation or recall
        *should also work for presented / recalled ints and floats, if desired

    Returns
    ----------
    subs_list_of_dfs : multi-indexed dataframe
        dataframe of subject data (presented or recalled words/items), indexed by subject and list number
        cell populated by the term presented or recalled in the position indicated by the column number

    """
    # set default index if it is not defined
    listindex = [idx for idx,lst in enumerate(all_data[0])] if not listindex else listindex
    subjindex = [idx for idx,subj in enumerate(all_data)] if not subjindex else subjindex

    def make_multi_index(listindex, sub_num):
        return pd.MultiIndex.from_tuples([(sub_num,lst) for lst in listindex], names = ['Subject', 'List'])

    listindex = list(listindex)
    subjindex = list(subjindex)

    subs_list_of_dfs = [pd.DataFrame(sub_data, index=make_multi_index(listindex, subjindex[sub_num])) for sub_num,sub_data in enumerate(all_data)]

    return pd.concat(subs_list_of_dfs)

def format2tidy(df, subjname, listname, subjgroup, analysis_type=None):
    melted_df = pd.melt(df.T)
    melted_df[subjname]=""
    for idx,sub in enumerate(melted_df['Subject'].unique()):
        melted_df.loc[melted_df['Subject']==sub,subjname]=subjgroup[idx]
    if analysis_type in ['spc']:
        base = list(df.columns)
        melted_df['Position'] = base * int(melted_df.shape[0] / len(base))
        melted_df.columns = ['Subject', listname, 'Proportion Recalled', subjname, 'Position']
    elif analysis_type in ['pfr']:
        base = list(df.columns)
        melted_df['Position'] = base * int(melted_df.shape[0] / len(base))
        melted_df.columns = ['Subject', listname, 'Probability of First Recall', subjname, 'Position']
    elif analysis_type is 'lagcrp':
        base = range(int(-len(df.columns.values)/2),0)+[0]+range(1,int(len(df.columns.values)/2)+1)
        melted_df['Position'] = base * int(melted_df.shape[0] / len(base))
        melted_df.columns = ['Subject', listname, 'Conditional Response Probability', subjname, 'Position']
    elif analysis_type is 'fingerprint':
        base = list(df.columns.values)
        melted_df['Feature'] = base * int(melted_df.shape[0] / len(base))
        melted_df.columns = ['Subject', listname, 'Clustering Score', subjname, 'Feature']
    elif analysis_type is 'accuracy':
        melted_df.columns = ['Subject', listname, 'Accuracy', subjname]

    return melted_df

def recmat2egg(recmat, list_length=None):
        """
        Creates egg data object from zero-indexed recall matrix

        Parameters
        ----------
        recmat : list of lists (subs) of lists (encoding lists) of ints or 2D numpy array
            recall matrix representing serial positions of freely recalled words \
            e.g. [[[16, 15, 0, 2, 3, None, None...], [16, 4, 5, 6, 1, None, None...]]]

        list_length : int
            The length of each list (e.g. 16)

        Returns
        ----------
        egg : Egg data object
            egg data object computed from the recall matrix
        """
        from .egg import Egg as Egg

        pres = [[[str(word) for word in list(range(0,list_length))] for reclist in recsub] for recsub in recmat]
        rec = [[[str(word) for word in reclist if word is not None] for reclist in recsub] for recsub in recmat]

        return Egg(pres=pres,rec=rec)

def default_dist_funcs(dist_funcs, feature_example):
        """
        Fills in default distance metrics for fingerprint analyses
        """

        for key in feature_example:
            if key in dist_funcs:
                pass
            elif type(feature_example[key]) is str:
                dist_funcs[key] = lambda a, b: int(a!=b)
            elif isinstance(feature_example[key], (int, long, float)) or all([isinstance(i, (int, long, float)) for i in feature_example[key]]):
                dist_funcs[key] = lambda a, b: np.linalg.norm(np.subtract(a,b))

        return dist_funcs

def stack_eggs(eggs):
    '''
    Takes a list of eggs, stacks them and reindexes the subject number

    Parameters
    ----------
    eggs : list of Egg data objects
        A list of Eggs that you want to combine

    Returns
    ----------
    new_egg : Egg data object
        A mega egg comprised of the input eggs stacked together

    '''
    from .egg import Egg

    pres = [egg.pres.loc[sub,:].values.tolist() for egg in eggs for sub in egg.pres.index.levels[0].values.tolist()]
    rec = [egg.rec.loc[sub,:].values.tolist()  for egg in eggs for sub in egg.rec.index.levels[0].values.tolist()]

    all_have_features = all([egg.features is not None for egg in eggs])

    if all_have_features:
        features = [egg.features.loc[sub,:].values.tolist() for egg in eggs for sub in egg.features.index.levels[0].values.tolist()]
        new_egg = Egg(pres=pres, rec=rec, features=features)
    else:
        new_egg = Egg(pres=pres, rec=rec)

    return new_egg

def crack_egg(egg, subjects=None, lists=None):
    '''
    Takes an egg and returns a subset of the subjects

    Parameters
    ----------
    egg : Egg data object
        Egg that you want to crack

    subjects : list
        List of subject idxs

    lists : list
        List of lists idxs

    Returns
    ----------
    new_egg : Egg data object
        A mega egg comprised of the input eggs stacked together

    '''
    from .egg import Egg

    all_have_features = egg.features is not None
    opts = {}

    if subjects is None:
        subjects = egg.pres.index.levels[0].values
    elif type(subjects) is not list:
        subjects = [subjects]
    if lists is None:
        lists = egg.pres.index.levels[1].values
    elif type(lists) is not list:
        lists = [lists]

    idx = pd.IndexSlice
    pres = egg.pres.loc[idx[subjects,lists],:]
    rec = egg.rec.loc[idx[subjects,lists],:]

    pres = [pres.loc[sub,:].values.tolist() for sub in pres.index.levels[0].values]
    rec = [rec.loc[sub,:].values.tolist() for sub in rec.index.levels[0].values]

    if all_have_features:
        features = egg.features.loc[idx[subjects,lists],:]
        opts['features'] = [features.loc[sub,:].values.tolist() for sub in features.index.levels[0].values]

    return Egg(pres=pres, rec=rec, **opts)
<commit_msg>added positions argument to crack_egg<commit_after>#!/usr/bin/env python

from __future__ import division
import pandas as pd
import numpy as np

def list2pd(all_data, subjindex=None, listindex=None):
    """
    Makes multi-indexed dataframe of subject data

    Parameters
    ----------
    all_data : list of lists of strings
        strings are either all presented or all recalled items, in the order of presentation or recall
        *should also work for presented / recalled ints and floats, if desired

    Returns
    ----------
    subs_list_of_dfs : multi-indexed dataframe
        dataframe of subject data (presented or recalled words/items), indexed by subject and list number
        cell populated by the term presented or recalled in the position indicated by the column number

    """
    # set default index if it is not defined
    listindex = [idx for idx,lst in enumerate(all_data[0])] if not listindex else listindex
    subjindex = [idx for idx,subj in enumerate(all_data)] if not subjindex else subjindex

    def make_multi_index(listindex, sub_num):
        return pd.MultiIndex.from_tuples([(sub_num,lst) for lst in listindex], names = ['Subject', 'List'])

    listindex = list(listindex)
    subjindex = list(subjindex)

    subs_list_of_dfs = [pd.DataFrame(sub_data, index=make_multi_index(listindex, subjindex[sub_num])) for sub_num,sub_data in enumerate(all_data)]

    return pd.concat(subs_list_of_dfs)

def format2tidy(df, subjname, listname, subjgroup, analysis_type=None):
    melted_df = pd.melt(df.T)
    melted_df[subjname]=""
    for idx,sub in enumerate(melted_df['Subject'].unique()):
        melted_df.loc[melted_df['Subject']==sub,subjname]=subjgroup[idx]
    if analysis_type in ['spc']:
        base = list(df.columns)
        melted_df['Position'] = base * int(melted_df.shape[0] / len(base))
        melted_df.columns = ['Subject', listname, 'Proportion Recalled', subjname, 'Position']
    elif analysis_type in ['pfr']:
        base = list(df.columns)
        melted_df['Position'] = base * int(melted_df.shape[0] / len(base))
        melted_df.columns = ['Subject', listname, 'Probability of First Recall', subjname, 'Position']
    elif analysis_type is 'lagcrp':
        base = range(int(-len(df.columns.values)/2),0)+[0]+range(1,int(len(df.columns.values)/2)+1)
        melted_df['Position'] = base * int(melted_df.shape[0] / len(base))
        melted_df.columns = ['Subject', listname, 'Conditional Response Probability', subjname, 'Position']
    elif analysis_type is 'fingerprint':
        base = list(df.columns.values)
        melted_df['Feature'] = base * int(melted_df.shape[0] / len(base))
        melted_df.columns = ['Subject', listname, 'Clustering Score', subjname, 'Feature']
    elif analysis_type is 'accuracy':
        melted_df.columns = ['Subject', listname, 'Accuracy', subjname]

    return melted_df

def recmat2egg(recmat, list_length=None):
        """
        Creates egg data object from zero-indexed recall matrix

        Parameters
        ----------
        recmat : list of lists (subs) of lists (encoding lists) of ints or 2D numpy array
            recall matrix representing serial positions of freely recalled words \
            e.g. [[[16, 15, 0, 2, 3, None, None...], [16, 4, 5, 6, 1, None, None...]]]

        list_length : int
            The length of each list (e.g. 16)

        Returns
        ----------
        egg : Egg data object
            egg data object computed from the recall matrix
        """
        from .egg import Egg as Egg

        pres = [[[str(word) for word in list(range(0,list_length))] for reclist in recsub] for recsub in recmat]
        rec = [[[str(word) for word in reclist if word is not None] for reclist in recsub] for recsub in recmat]

        return Egg(pres=pres,rec=rec)

def default_dist_funcs(dist_funcs, feature_example):
        """
        Fills in default distance metrics for fingerprint analyses
        """

        for key in feature_example:
            if key in dist_funcs:
                pass
            elif type(feature_example[key]) is str:
                dist_funcs[key] = lambda a, b: int(a!=b)
            elif isinstance(feature_example[key], (int, long, float)) or all([isinstance(i, (int, long, float)) for i in feature_example[key]]):
                dist_funcs[key] = lambda a, b: np.linalg.norm(np.subtract(a,b))

        return dist_funcs

def stack_eggs(eggs):
    '''
    Takes a list of eggs, stacks them and reindexes the subject number

    Parameters
    ----------
    eggs : list of Egg data objects
        A list of Eggs that you want to combine

    Returns
    ----------
    new_egg : Egg data object
        A mega egg comprised of the input eggs stacked together

    '''
    from .egg import Egg

    pres = [egg.pres.loc[sub,:].values.tolist() for egg in eggs for sub in egg.pres.index.levels[0].values.tolist()]
    rec = [egg.rec.loc[sub,:].values.tolist()  for egg in eggs for sub in egg.rec.index.levels[0].values.tolist()]

    all_have_features = all([egg.features is not None for egg in eggs])

    if all_have_features:
        features = [egg.features.loc[sub,:].values.tolist() for egg in eggs for sub in egg.features.index.levels[0].values.tolist()]
        new_egg = Egg(pres=pres, rec=rec, features=features)
    else:
        new_egg = Egg(pres=pres, rec=rec)

    return new_egg

def crack_egg(egg, subjects=None, lists=None, positions=None):
    '''
    Takes an egg and returns a subset of the subjects

    Parameters
    ----------
    egg : Egg data object
        Egg that you want to crack

    subjects : list
        List of subject idxs

    lists : list
        List of lists idxs

    positions : list
        List of position idxs

    Returns
    ----------
    new_egg : Egg data object
        A mega egg comprised of the input eggs stacked together

    '''
    from .egg import Egg

    all_have_features = egg.features is not None
    opts = {}

    if subjects is None:
        subjects = egg.pres.index.levels[0].values
    elif type(subjects) is not list:
        subjects = [subjects]

    if lists is None:
        lists = egg.pres.index.levels[1].values
    elif type(lists) is not list:
        lists = [lists]

    if positions is None:
        positions = egg.pres.index.levels[1].values
    elif type(lists) is not list:
        lists = [lists]

    idx = pd.IndexSlice
    pres = egg.pres.loc[idx[subjects,lists],positions]
    rec = egg.rec.loc[idx[subjects,lists],positions]

    pres = [pres.loc[sub,:].values.tolist() for sub in pres.index.levels[0].values]
    rec = [rec.loc[sub,:].values.tolist() for sub in rec.index.levels[0].values]

    if all_have_features:
        features = egg.features.loc[idx[subjects,lists],positions]
        opts['features'] = [features.loc[sub,:].values.tolist() for sub in features.index.levels[0].values]

    return Egg(pres=pres, rec=rec, **opts)
<|endoftext|>


<commit_before>#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
import os

class HomeHandler(webapp.RequestHandler):
    def get(self):
		self.response.out.write("""

					<title>Myanmar Web Font</title>

Supported Unicode Fonts are
					Yunghkio, Myanmar3 , Paduk, Parabaik.

Also support Zawgyi-One

CSS link

Yunghkio

						<link href='http://mywebfont.appspot.com/css?font=yunghkio' rel='stylesheet' type='text/css'>

Myanmar3

						<link href='http://mywebfont.appspot.com/css?font=myanmar3' rel='stylesheet' type='text/css'>

Padauk

						<link href='http://mywebfont.appspot.com/css?font=padauk' rel='stylesheet' type='text/css'>

Parabaik

						<link href='http://mywebfont.appspot.com/css?font=parabaik' rel='stylesheet' type='text/css'>

Zawgyi-One

						<link href='http://mywebfont.appspot.com/css?font=zawgyi' rel='stylesheet' type='text/css'>

Need to do

					You need to declare font-family in CSS like following

						h1 { font-family:"Masterpiece Uni Sans",Yunghkio,Myanmar3}

						I recommend to start with Masterpiece Uni Sans.It's for some peple who use iOS or Mac. Mac and iOS can use Masterpiece only. So, please start with "Masterpiece Uni Sans".

		""")
class MainHandler(webapp.RequestHandler):
    def get(self):
		#check font name
		font_family="Master Piece Uni Sans"
		font_file=self.request.get("font").lower();
		if(self.request.get("font").lower()=='yunghkio'):
			font_family="Yunghkio"
		elif(self.request.get("font").lower()=='myanmar3'):
			font_family="Myanmar3"
		elif(self.request.get("font").lower()=='padauk'):
			font_family="Padauk"
		elif(self.request.get("font").lower()=='parabaik'):
			font_family="Parabaik"

		browsername=Getbrowsername()
		font_type=""

		#check browser .. Myanmar Unicode Font Embed only work on firefox, opera and ie
		if(browsername=='firefox' or browsername=='opera' or browsername=='chrome' ):
			font_type='ttf'
		elif(browsername=='ie'):
			font_type='eot'

		#not supported on mac
		if(mac_os()):
			font_type=""

		#check and forece Masterpiece if OS is apple related
		if(browsername=='iPhone' or browsername=='iPad' or (mac_os() and browsername=='safari')):
			font_family="Masterpiece Uni Sans"
			font_file="masterpiece"
			font_type="ttf"

		#zawgyi font support all browser
		if(self.request.get("font").lower()=='zawgyi'):
			font_family="Zawgyi-One"
			font_file="zawgyi"
			font_type="ttf"

		if(self.request.get("font").lower()=='zawgyi' and browsername=='ie'):
			font_family="Zawgyi-One"
			font_file="zawgyi"
			font_type="eot"

		#check font type to load or not. Unicode font can't load in Android and chrome
		if(font_type!=""):
			css="@font-face {\nfont-family:"+font_family+";"

			if(browsername!='ie'):
				css+="\nsrc:local('"+font_family+"'),"

			font_path=self.request.host_url+"/font/"+font_file+"."+font_type

			if(browsername!='ie'):
				css+="url('"+font_path+"');\n}"
			else:
				css+="\nsrc:url('"+font_path+"');"
				css+="\nsrc:local('"+font_family+"');\n}"

			self.response.headers["Access-Control-Allow-Origin"] = "*"
			self.response.headers["Content-Type"] = "text/css"
			self.response.out.write(css)

def Getbrowsername():
	if(os.environ['HTTP_USER_AGENT'].find('iPhone')!=-1):
		return "iPhone"
	elif(os.environ['HTTP_USER_AGENT'].find('iPad')!=-1):
		return "iPad"
	elif(os.environ['HTTP_USER_AGENT'].find('Chrome')!=-1):
		return "chrome"
	elif(os.environ['HTTP_USER_AGENT'].find('Safari')!=-1):
		return "safari"
	elif(os.environ['HTTP_USER_AGENT'].find('Firefox')!=-1):
		return "firefox"
	elif(os.environ['HTTP_USER_AGENT'].find('Opera')!=-1):
		return "opera"
	elif(os.environ['HTTP_USER_AGENT'].find('MSIE')!=-1):
		return "ie"

def mac_os():
	if(os.environ['HTTP_USER_AGENT'].find('Mac')!=-1):
		return True
	return False

def main():
    application = webapp.WSGIApplication([('/',HomeHandler),('/css', MainHandler)],
                                         debug=True)
    util.run_wsgi_app(application)

if __name__ == '__main__':
    main()
<commit_msg>add example<commit_after>#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
import os

class HomeHandler(webapp.RequestHandler):
    def get(self):
		self.response.out.write("""

					<title>Myanmar Web Font</title>

Supported Unicode Fonts are
					Yunghkio, Myanmar3 , Paduk, Parabaik.

Also support Zawgyi-One

CSS link

Yunghkio

						<link href='http://mywebfont.appspot.com/css?font=yunghkio' rel='stylesheet' type='text/css'/>

Myanmar3

						<link href='http://mywebfont.appspot.com/css?font=myanmar3' rel='stylesheet' type='text/css/'>

Padauk

						<link href='http://mywebfont.appspot.com/css?font=padauk' rel='stylesheet' type='text/css'/>

Parabaik

						<link href='http://mywebfont.appspot.com/css?font=parabaik' rel='stylesheet' type='text/css'/>

Zawgyi-One

						<link href='http://mywebfont.appspot.com/css?font=zawgyi' rel='stylesheet' type='text/css'/>

Need to do

					You need to declare font-family in CSS like following

						h1 { font-family:"Masterpiece Uni Sans",Yunghkio,Myanmar3}

Sample

Other

						I recommend to start with Masterpiece Uni Sans.It's for some peple who use iOS or Mac. Mac and iOS can use Masterpiece only. So, please start with "Masterpiece Uni Sans".

		""")
class MainHandler(webapp.RequestHandler):
    def get(self):
		#check font name
		font_family="Master Piece Uni Sans"
		font_file=self.request.get("font").lower();
		if(self.request.get("font").lower()=='yunghkio'):
			font_family="Yunghkio"
		elif(self.request.get("font").lower()=='myanmar3'):
			font_family="Myanmar3"
		elif(self.request.get("font").lower()=='padauk'):
			font_family="Padauk"
		elif(self.request.get("font").lower()=='parabaik'):
			font_family="Parabaik"

		browsername=Getbrowsername()
		font_type=""

		#check browser .. Myanmar Unicode Font Embed only work on firefox, opera and ie
		if(browsername=='firefox' or browsername=='opera' or browsername=='chrome' ):
			font_type='ttf'
		elif(browsername=='ie'):
			font_type='eot'

		#not supported on mac
		if(mac_os()):
			font_type=""

		#check and forece Masterpiece if OS is apple related
		if(browsername=='iPhone' or browsername=='iPad' or (mac_os() and browsername=='safari')):
			font_family="Masterpiece Uni Sans"
			font_file="masterpiece"
			font_type="ttf"

		#zawgyi font support all browser
		if(self.request.get("font").lower()=='zawgyi'):
			font_family="Zawgyi-One"
			font_file="zawgyi"
			font_type="ttf"

		if(self.request.get("font").lower()=='zawgyi' and browsername=='ie'):
			font_family="Zawgyi-One"
			font_file="zawgyi"
			font_type="eot"

		#check font type to load or not. Unicode font can't load in Android and chrome
		if(font_type!=""):
			css="@font-face {\nfont-family:"+font_family+";"

			if(browsername!='ie'):
				css+="\nsrc:local('"+font_family+"'),"

			font_path=self.request.host_url+"/font/"+font_file+"."+font_type

			if(browsername!='ie'):
				css+="url('"+font_path+"');\n}"
			else:
				css+="\nsrc:url('"+font_path+"');"
				css+="\nsrc:local('"+font_family+"');\n}"

			self.response.headers["Access-Control-Allow-Origin"] = "*"
			self.response.headers["Content-Type"] = "text/css"
			self.response.out.write(css)

def Getbrowsername():
	if(os.environ['HTTP_USER_AGENT'].find('iPhone')!=-1):
		return "iPhone"
	elif(os.environ['HTTP_USER_AGENT'].find('iPad')!=-1):
		return "iPad"
	elif(os.environ['HTTP_USER_AGENT'].find('Chrome')!=-1):
		return "chrome"
	elif(os.environ['HTTP_USER_AGENT'].find('Safari')!=-1):
		return "safari"
	elif(os.environ['HTTP_USER_AGENT'].find('Firefox')!=-1):
		return "firefox"
	elif(os.environ['HTTP_USER_AGENT'].find('Opera')!=-1):
		return "opera"
	elif(os.environ['HTTP_USER_AGENT'].find('MSIE')!=-1):
		return "ie"

def mac_os():
	if(os.environ['HTTP_USER_AGENT'].find('Mac')!=-1):
		return True
	return False

def main():
    application = webapp.WSGIApplication([('/',HomeHandler),('/css', MainHandler)],
                                         debug=True)
    util.run_wsgi_app(application)

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


<commit_before>
import discord
from discord.ext import commands

import typing

from utilities import checks

def setup(bot):
	bot.add_cog(Pinboard(bot))

class Pinboard(commands.Cog):

	def __init__(self, bot):
		self.bot = bot
		self.default_threshold = 3
		self.pin_emotes = ("\N{PUSHPIN}", "\N{ROUND PUSHPIN}",
							"\N{WHITE MEDIUM STAR}", "\N{GLOWING STAR}", "\N{SHOOTING STAR}")
		self.bot.loop.create_task(self.initialize_database())

	async def initialize_database(self):
		await self.bot.connect_to_database()
		await self.bot.db.execute("CREATE SCHEMA IF NOT EXISTS pinboard")
		await self.bot.db.execute(
			"""
			CREATE TABLE IF NOT EXISTS pinboard.pinboards (
				guild_id			BIGINT PRIMARY KEY,
				channel_id			BIGINT,
				threshold			INT,
				private_channels	BOOL
			)
			"""
		)
		await self.bot.db.execute(
			"""
			CREATE TABLE IF NOT EXISTS pinboard.pins (
				message_id			BIGINT PRIMARY KEY,
				guild_id			BIGINT,
				channel_id			BIGINT,
				pinboard_message_id BIGINT
			)
			"""
		)
		await self.bot.db.execute(
			"""
			CREATE TABLE IF NOT EXISTS pinboard.pinners (
				message_id	BIGINT REFERENCES pinboard.pins (message_id) ON DELETE CASCADE,
				pinner_id	BIGINT,
				PRIMARY KEY (message_id, pinner_id)
			)
			"""
		)

	@commands.group(aliases = ["starboard"], invoke_without_command = True)
	@commands.is_owner()
	async def pinboard(self, ctx):
		'''
		WIP
		Pinboard/Starboard
		Inspired by Rapptz/Danny's Robo/R. Danny's starboard
		'''
		await ctx.send_help(ctx.command)

	@pinboard.command()
	@checks.is_permitted()
	async def backfill(self, ctx):
		'''
		Backfill pins into current pinboard channel
		This can take a while depending on how many missing pinned messages there are
		'''
		record = await ctx.bot.db.fetchrow(
			"""
			SELECT channel_id, threshold, private_channels
			FROM pinboard.pinboards
			WHERE guild_id = $1
			""",
			ctx.guild.id
		)
		pinboard_channel_id = record["channel_id"]
		threshold = record["threshold"] or self.default_threshold
		private_channels_setting = record["private_channels"]
		if not pinboard_channel_id:
			return await ctx.embed_reply(":no_entry: Error: Pinboard channel not set")
		response = await ctx.embed_reply("Backfilling...")
		pinboard_channel = self.bot.get_channel(pinboard_channel_id)
		async with ctx.bot.database_connection_pool.acquire() as connection:
			async with connection.transaction():
				# Postgres requires non-scrollable cursors to be created
				# and used in a transaction.
				async for record in connection.cursor("SELECT * FROM pinboard.pins WHERE guild_id = $1 ORDER BY message_id",
														ctx.guild.id):
					try:
						await pinboard_channel.fetch_message(record["pinboard_message_id"])
					except (discord.NotFound, discord.HTTPException):
						pin_count = await self.bot.db.fetchval("SELECT COUNT(*) FROM pinboard.pinners WHERE message_id = $1",
																record["message_id"])
						if pin_count < threshold:
							continue
						pinned_message_channel = self.bot.get_channel(record["channel_id"])
						if not private_channels_setting and pinned_message_channel.overwrites_for(ctx.guild.default_role).read_messages == False:
							continue
						pinned_message = await pinned_message_channel.fetch_message(record["message_id"])
						pinboard_message = await self.send_pinboard_message(pinboard_channel, pinned_message, pin_count)
						await self.bot.db.execute("UPDATE pinboard.pins SET pinboard_message_id = $1 WHERE message_id = $2",
													pinboard_message.id, record["message_id"])
		if ctx.channel.id == pinboard_channel_id:
			await ctx.bot.attempt_delete_message(response)
		else:
			embed = response.embeds[0]
			embed.description = "Backfill complete"
			await response.edit(embed = embed)

	# TODO: pinboard off option
	@pinboard.command()
	@checks.is_permitted()
	async def channel(self, ctx, channel : discord.TextChannel = None):
		'''Set/get channel'''
		channel_id = await ctx.bot.db.fetchval("SELECT channel_id FROM pinboard.pinboards WHERE guild_id = $1",
												ctx.guild.id)
		if not channel_id:
			if not channel:
				channel = ctx.channel
			await ctx.bot.db.execute("INSERT INTO pinboard.pinboards (guild_id, channel_id) VALUES ($1, $2)",
										ctx.guild.id, channel.id)
			await ctx.embed_reply(f":thumbsup::skin-tone-2: Pinboard channel set to {channel.mention}")
		elif not channel:
			pinboard_channel = ctx.guild.get_channel(channel_id)
			await ctx.embed_reply(f"Current pinboard channel: {pinboard_channel.mention}")
		else:
			await ctx.bot.db.execute("UPDATE pinboard.pinboards SET channel_id = $1 WHERE guild_id = $2",
										channel.id, ctx.guild.id)
			await ctx.embed_reply(f":thumbsup::skin-tone-2: Changed pinboard channel to {channel.mention}")

	@pinboard.command(aliases = ["starrers", "who"])
	@checks.not_forbidden()
	async def pinners(self, ctx, message_id : int):
		'''
		Show who pinned a message
		message_id can be the message ID for the pinned message or the message in the pinboard channel
		'''
		records = await ctx.bot.db.fetch(
			"""
			SELECT pinboard.pinners.pinner_id
			FROM pinboard.pinners
			INNER JOIN pinboard.pins
			ON pinboard.pinners.message_id = pinboard.pins.message_id
			WHERE pinboard.pins.message_id = $1 OR pinboard.pins.pinboard_message_id = $1
			""",
			message_id
		)
		if not records:
			return await ctx.embed_reply("No one has pinned this message or this is not a valid message ID")
		pinners = []
		for record in records:
			pinner = ctx.bot.get_user(record[0])
			if not pinner:
				pinner = await ctx.bot.fetch_user(record[0])
			pinners.append(pinner)
		await ctx.embed_reply(' '.join(pinner.mention for pinner in pinners),
								title = f"{len(records)} pinners of {message_id}")

	@pinboard.command(aliases = ["private"])
	@checks.is_permitted()
	async def private_channels(self, ctx, setting : typing.Optional[bool]):
		'''
		Set/get whether to include pins from private channels
		Default: False
		A channel is considered private if the "Read Messages" permission is off for the everyone role
		'''
		# TODO: Handle case where guild-level "Read Messages" permission is off for @everyone?
		if setting is None:
			setting = await ctx.bot.db.fetchval(
				"""
				SELECT private_channels
				FROM pinboard.pinboards
				WHERE guild_id = $1
				""",
				ctx.guild.id
			)
			if setting is None:
				await ctx.embed_reply(f"Current pinboard setting: Ignore private channels (Default)")
			elif setting:
				await ctx.embed_reply(f"Current pinboard setting: Include private channels")
			else:
				await ctx.embed_reply(f"Current pinboard setting: Ignore private channels")
		else:
			await ctx.bot.db.execute(
				"""
				UPDATE pinboard.pinboards
				SET private_channels = $1
				WHERE guild_id = $2
				""",
				setting, ctx.guild.id
			)
			await ctx.embed_reply(f":thumbsup::skin-tone-2: Changed pinboard private channels setting to {setting}")

	@pinboard.command()
	@checks.is_permitted()
	async def threshold(self, ctx, threshold_number : int = None):
		'''
		Set/get the number of reactions needed to pin message
		Default: 3
		'''
		if threshold_number:
			await ctx.bot.db.execute("UPDATE pinboard.pinboards SET threshold = $1 WHERE guild_id = $2",
										threshold_number, ctx.guild.id)
			await ctx.embed_reply(f":thumbsup::skin-tone-2: Changed pinboard threshold to {threshold_number}")
		else:
			threshold_number = await ctx.bot.db.fetchval("SELECT threshold FROM pinboard.pinboards WHERE guild_id = $1",
															ctx.guild.id)
			if threshold_number:
				await ctx.embed_reply(f"Current pinboard threshold: {threshold_number}")
			else:
				await ctx.embed_reply(f"The current pinboard threshold is the default of 3")

	@commands.Cog.listener()
	async def on_raw_reaction_add(self, payload):
		if str(payload.emoji) not in self.pin_emotes:
			# Reaction is not for pinboard
			return
		if not payload.guild_id:
			# Reaction is not in a guild
			return
		record = await self.bot.db.fetchrow(
			"""
			SELECT channel_id, threshold, private_channels
			FROM pinboard.pinboards
			WHERE guild_id = $1
			""",
			payload.guild_id
		)
		if not record:
			# Guild doesn't have a pinboard
			return
		pinboard_channel_id = record["channel_id"]
		threshold = record["threshold"] or self.default_threshold
		private_channels_setting = record["private_channels"]
		if payload.channel_id == pinboard_channel_id:
			# Message being reacted to is on the pinboard
			pinboard_message_id = payload.message_id
			record = await self.bot.db.fetchrow(
				"""
				SELECT message_id, channel_id
				FROM pinboard.pins WHERE pinboard_message_id = $1
				""",
				pinboard_message_id
			)
			message_id = record["message_id"]
			channel_id = record["channel_id"]
		else:
			message_id = payload.message_id
			channel_id = payload.channel_id
			pinboard_message_id = await self.bot.db.fetchval(
				"""
				INSERT INTO pinboard.pins (message_id, guild_id, channel_id)
				VALUES ($1, $2, $3)
				ON CONFLICT (message_id) DO UPDATE SET guild_id = $2
				RETURNING pinboard_message_id
				""",
				message_id, payload.guild_id, payload.channel_id
			)
		# Add user as pinner
		inserted = await self.bot.db.fetchrow(
			"""
			INSERT INTO pinboard.pinners (message_id, pinner_id)
			VALUES ($1, $2)
			ON CONFLICT DO NOTHING
			RETURNING *
			""",
			message_id, payload.user_id
		)
		if not inserted:
			# User has already pinned this message
			return
		pin_count = await self.bot.db.fetchval("SELECT COUNT(*) FROM pinboard.pinners WHERE message_id = $1",
												message_id)
		if pin_count < threshold:
			# Pin count has not reached threshold yet
			return
		guild = self.bot.get_guild(payload.guild_id)
		pinboard_channel = self.bot.get_channel(pinboard_channel_id)
		pinned_message_channel = self.bot.get_channel(channel_id)
		if not private_channels_setting and pinned_message_channel.overwrites_for(guild.default_role).read_messages == False:
			# Set to ignore private channels and message is in private channel
			return
		pinned_message = await pinned_message_channel.fetch_message(message_id)
		if pinboard_message_id:
			# Pinboard message already exists
			pinboard_message = await pinboard_channel.fetch_message(pinboard_message_id)
			embed = pinboard_message.embeds[0]
			embed.clear_fields()
			embed.add_field(name = f"**{pin_count}** \N{PUSHPIN}", value = f"[Message Link]({pinned_message.jump_url})")
			await pinboard_message.edit(embed = embed)
		else:
			pinboard_message = await self.send_pinboard_message(pinboard_channel, pinned_message, pin_count)
			await self.bot.db.execute("UPDATE pinboard.pins SET pinboard_message_id = $1 WHERE message_id = $2",
										pinboard_message.id, message_id)

	async def send_pinboard_message(self, pinboard_channel, pinned_message, pin_count):
		# TODO: custom emote
		embed = discord.Embed(timestamp = pinned_message.created_at, color = 0xdd2e44)
		# TODO: color dependent on custom emote
		# alternate color: 0xbe1931
		# star: 0xffac33
		embed.set_author(name = pinned_message.author.display_name, icon_url = pinned_message.author.avatar_url)
		content = pinned_message.content
		if pinned_message.embeds:
			if pinned_message.embeds[0].type == "image":
				embed.set_image(url = pinned_message.embeds[0].thumbnail.url)
			else:
				content += '\n' + self.bot.CODE_BLOCK.format(pinned_message.embeds[0].to_dict())
		embed.description = content
		if pinned_message.attachments:
			embed.set_image(url = pinned_message.attachments[0].url)
		# TODO: Handle non-image attachments
		# TODO: Handle both attachments and image embed?
		embed.add_field(name = f"**{pin_count}** \N{PUSHPIN}", value = f"[Message Link]({pinned_message.jump_url})")
		embed.set_footer(text = f"In #{pinned_message.channel}")
		return await pinboard_channel.send(embed = embed)

<commit_msg>[Discord] Improve type hint formatting for pinners command<commit_after>
import discord
from discord.ext import commands

import typing

from utilities import checks

def setup(bot):
	bot.add_cog(Pinboard(bot))

class Pinboard(commands.Cog):

	def __init__(self, bot):
		self.bot = bot
		self.default_threshold = 3
		self.pin_emotes = ("\N{PUSHPIN}", "\N{ROUND PUSHPIN}",
							"\N{WHITE MEDIUM STAR}", "\N{GLOWING STAR}", "\N{SHOOTING STAR}")
		self.bot.loop.create_task(self.initialize_database())

	async def initialize_database(self):
		await self.bot.connect_to_database()
		await self.bot.db.execute("CREATE SCHEMA IF NOT EXISTS pinboard")
		await self.bot.db.execute(
			"""
			CREATE TABLE IF NOT EXISTS pinboard.pinboards (
				guild_id			BIGINT PRIMARY KEY,
				channel_id			BIGINT,
				threshold			INT,
				private_channels	BOOL
			)
			"""
		)
		await self.bot.db.execute(
			"""
			CREATE TABLE IF NOT EXISTS pinboard.pins (
				message_id			BIGINT PRIMARY KEY,
				guild_id			BIGINT,
				channel_id			BIGINT,
				pinboard_message_id BIGINT
			)
			"""
		)
		await self.bot.db.execute(
			"""
			CREATE TABLE IF NOT EXISTS pinboard.pinners (
				message_id	BIGINT REFERENCES pinboard.pins (message_id) ON DELETE CASCADE,
				pinner_id	BIGINT,
				PRIMARY KEY (message_id, pinner_id)
			)
			"""
		)

	@commands.group(aliases = ["starboard"], invoke_without_command = True)
	@commands.is_owner()
	async def pinboard(self, ctx):
		'''
		WIP
		Pinboard/Starboard
		Inspired by Rapptz/Danny's Robo/R. Danny's starboard
		'''
		await ctx.send_help(ctx.command)

	@pinboard.command()
	@checks.is_permitted()
	async def backfill(self, ctx):
		'''
		Backfill pins into current pinboard channel
		This can take a while depending on how many missing pinned messages there are
		'''
		record = await ctx.bot.db.fetchrow(
			"""
			SELECT channel_id, threshold, private_channels
			FROM pinboard.pinboards
			WHERE guild_id = $1
			""",
			ctx.guild.id
		)
		pinboard_channel_id = record["channel_id"]
		threshold = record["threshold"] or self.default_threshold
		private_channels_setting = record["private_channels"]
		if not pinboard_channel_id:
			return await ctx.embed_reply(":no_entry: Error: Pinboard channel not set")
		response = await ctx.embed_reply("Backfilling...")
		pinboard_channel = self.bot.get_channel(pinboard_channel_id)
		async with ctx.bot.database_connection_pool.acquire() as connection:
			async with connection.transaction():
				# Postgres requires non-scrollable cursors to be created
				# and used in a transaction.
				async for record in connection.cursor("SELECT * FROM pinboard.pins WHERE guild_id = $1 ORDER BY message_id",
														ctx.guild.id):
					try:
						await pinboard_channel.fetch_message(record["pinboard_message_id"])
					except (discord.NotFound, discord.HTTPException):
						pin_count = await self.bot.db.fetchval("SELECT COUNT(*) FROM pinboard.pinners WHERE message_id = $1",
																record["message_id"])
						if pin_count < threshold:
							continue
						pinned_message_channel = self.bot.get_channel(record["channel_id"])
						if not private_channels_setting and pinned_message_channel.overwrites_for(ctx.guild.default_role).read_messages == False:
							continue
						pinned_message = await pinned_message_channel.fetch_message(record["message_id"])
						pinboard_message = await self.send_pinboard_message(pinboard_channel, pinned_message, pin_count)
						await self.bot.db.execute("UPDATE pinboard.pins SET pinboard_message_id = $1 WHERE message_id = $2",
													pinboard_message.id, record["message_id"])
		if ctx.channel.id == pinboard_channel_id:
			await ctx.bot.attempt_delete_message(response)
		else:
			embed = response.embeds[0]
			embed.description = "Backfill complete"
			await response.edit(embed = embed)

	# TODO: pinboard off option
	@pinboard.command()
	@checks.is_permitted()
	async def channel(self, ctx, channel : discord.TextChannel = None):
		'''Set/get channel'''
		channel_id = await ctx.bot.db.fetchval("SELECT channel_id FROM pinboard.pinboards WHERE guild_id = $1",
												ctx.guild.id)
		if not channel_id:
			if not channel:
				channel = ctx.channel
			await ctx.bot.db.execute("INSERT INTO pinboard.pinboards (guild_id, channel_id) VALUES ($1, $2)",
										ctx.guild.id, channel.id)
			await ctx.embed_reply(f":thumbsup::skin-tone-2: Pinboard channel set to {channel.mention}")
		elif not channel:
			pinboard_channel = ctx.guild.get_channel(channel_id)
			await ctx.embed_reply(f"Current pinboard channel: {pinboard_channel.mention}")
		else:
			await ctx.bot.db.execute("UPDATE pinboard.pinboards SET channel_id = $1 WHERE guild_id = $2",
										channel.id, ctx.guild.id)
			await ctx.embed_reply(f":thumbsup::skin-tone-2: Changed pinboard channel to {channel.mention}")

	@pinboard.command(aliases = ["starrers", "who"])
	@checks.not_forbidden()
	async def pinners(self, ctx, message_id: int):
		'''
		Show who pinned a message
		message_id can be the message ID for the pinned message or the message in the pinboard channel
		'''
		records = await ctx.bot.db.fetch(
			"""
			SELECT pinboard.pinners.pinner_id
			FROM pinboard.pinners
			INNER JOIN pinboard.pins
			ON pinboard.pinners.message_id = pinboard.pins.message_id
			WHERE pinboard.pins.message_id = $1 OR pinboard.pins.pinboard_message_id = $1
			""",
			message_id
		)
		if not records:
			return await ctx.embed_reply("No one has pinned this message or this is not a valid message ID")
		pinners = []
		for record in records:
			pinner = ctx.bot.get_user(record[0])
			if not pinner:
				pinner = await ctx.bot.fetch_user(record[0])
			pinners.append(pinner)
		await ctx.embed_reply(' '.join(pinner.mention for pinner in pinners),
								title = f"{len(records)} pinners of {message_id}")

	@pinboard.command(aliases = ["private"])
	@checks.is_permitted()
	async def private_channels(self, ctx, setting : typing.Optional[bool]):
		'''
		Set/get whether to include pins from private channels
		Default: False
		A channel is considered private if the "Read Messages" permission is off for the everyone role
		'''
		# TODO: Handle case where guild-level "Read Messages" permission is off for @everyone?
		if setting is None:
			setting = await ctx.bot.db.fetchval(
				"""
				SELECT private_channels
				FROM pinboard.pinboards
				WHERE guild_id = $1
				""",
				ctx.guild.id
			)
			if setting is None:
				await ctx.embed_reply(f"Current pinboard setting: Ignore private channels (Default)")
			elif setting:
				await ctx.embed_reply(f"Current pinboard setting: Include private channels")
			else:
				await ctx.embed_reply(f"Current pinboard setting: Ignore private channels")
		else:
			await ctx.bot.db.execute(
				"""
				UPDATE pinboard.pinboards
				SET private_channels = $1
				WHERE guild_id = $2
				""",
				setting, ctx.guild.id
			)
			await ctx.embed_reply(f":thumbsup::skin-tone-2: Changed pinboard private channels setting to {setting}")

	@pinboard.command()
	@checks.is_permitted()
	async def threshold(self, ctx, threshold_number : int = None):
		'''
		Set/get the number of reactions needed to pin message
		Default: 3
		'''
		if threshold_number:
			await ctx.bot.db.execute("UPDATE pinboard.pinboards SET threshold = $1 WHERE guild_id = $2",
										threshold_number, ctx.guild.id)
			await ctx.embed_reply(f":thumbsup::skin-tone-2: Changed pinboard threshold to {threshold_number}")
		else:
			threshold_number = await ctx.bot.db.fetchval("SELECT threshold FROM pinboard.pinboards WHERE guild_id = $1",
															ctx.guild.id)
			if threshold_number:
				await ctx.embed_reply(f"Current pinboard threshold: {threshold_number}")
			else:
				await ctx.embed_reply(f"The current pinboard threshold is the default of 3")

	@commands.Cog.listener()
	async def on_raw_reaction_add(self, payload):
		if str(payload.emoji) not in self.pin_emotes:
			# Reaction is not for pinboard
			return
		if not payload.guild_id:
			# Reaction is not in a guild
			return
		record = await self.bot.db.fetchrow(
			"""
			SELECT channel_id, threshold, private_channels
			FROM pinboard.pinboards
			WHERE guild_id = $1
			""",
			payload.guild_id
		)
		if not record:
			# Guild doesn't have a pinboard
			return
		pinboard_channel_id = record["channel_id"]
		threshold = record["threshold"] or self.default_threshold
		private_channels_setting = record["private_channels"]
		if payload.channel_id == pinboard_channel_id:
			# Message being reacted to is on the pinboard
			pinboard_message_id = payload.message_id
			record = await self.bot.db.fetchrow(
				"""
				SELECT message_id, channel_id
				FROM pinboard.pins WHERE pinboard_message_id = $1
				""",
				pinboard_message_id
			)
			message_id = record["message_id"]
			channel_id = record["channel_id"]
		else:
			message_id = payload.message_id
			channel_id = payload.channel_id
			pinboard_message_id = await self.bot.db.fetchval(
				"""
				INSERT INTO pinboard.pins (message_id, guild_id, channel_id)
				VALUES ($1, $2, $3)
				ON CONFLICT (message_id) DO UPDATE SET guild_id = $2
				RETURNING pinboard_message_id
				""",
				message_id, payload.guild_id, payload.channel_id
			)
		# Add user as pinner
		inserted = await self.bot.db.fetchrow(
			"""
			INSERT INTO pinboard.pinners (message_id, pinner_id)
			VALUES ($1, $2)
			ON CONFLICT DO NOTHING
			RETURNING *
			""",
			message_id, payload.user_id
		)
		if not inserted:
			# User has already pinned this message
			return
		pin_count = await self.bot.db.fetchval("SELECT COUNT(*) FROM pinboard.pinners WHERE message_id = $1",
												message_id)
		if pin_count < threshold:
			# Pin count has not reached threshold yet
			return
		guild = self.bot.get_guild(payload.guild_id)
		pinboard_channel = self.bot.get_channel(pinboard_channel_id)
		pinned_message_channel = self.bot.get_channel(channel_id)
		if not private_channels_setting and pinned_message_channel.overwrites_for(guild.default_role).read_messages == False:
			# Set to ignore private channels and message is in private channel
			return
		pinned_message = await pinned_message_channel.fetch_message(message_id)
		if pinboard_message_id:
			# Pinboard message already exists
			pinboard_message = await pinboard_channel.fetch_message(pinboard_message_id)
			embed = pinboard_message.embeds[0]
			embed.clear_fields()
			embed.add_field(name = f"**{pin_count}** \N{PUSHPIN}", value = f"[Message Link]({pinned_message.jump_url})")
			await pinboard_message.edit(embed = embed)
		else:
			pinboard_message = await self.send_pinboard_message(pinboard_channel, pinned_message, pin_count)
			await self.bot.db.execute("UPDATE pinboard.pins SET pinboard_message_id = $1 WHERE message_id = $2",
										pinboard_message.id, message_id)

	async def send_pinboard_message(self, pinboard_channel, pinned_message, pin_count):
		# TODO: custom emote
		embed = discord.Embed(timestamp = pinned_message.created_at, color = 0xdd2e44)
		# TODO: color dependent on custom emote
		# alternate color: 0xbe1931
		# star: 0xffac33
		embed.set_author(name = pinned_message.author.display_name, icon_url = pinned_message.author.avatar_url)
		content = pinned_message.content
		if pinned_message.embeds:
			if pinned_message.embeds[0].type == "image":
				embed.set_image(url = pinned_message.embeds[0].thumbnail.url)
			else:
				content += '\n' + self.bot.CODE_BLOCK.format(pinned_message.embeds[0].to_dict())
		embed.description = content
		if pinned_message.attachments:
			embed.set_image(url = pinned_message.attachments[0].url)
		# TODO: Handle non-image attachments
		# TODO: Handle both attachments and image embed?
		embed.add_field(name = f"**{pin_count}** \N{PUSHPIN}", value = f"[Message Link]({pinned_message.jump_url})")
		embed.set_footer(text = f"In #{pinned_message.channel}")
		return await pinboard_channel.send(embed = embed)

<|endoftext|>


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

from __future__ import print_function

import argparse
import logging

from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
from neutronclient.openstack.common.gettextutils import _

def _format_external_gateway_info(router):
    try:
        return utils.dumps(router['external_gateway_info'])
    except Exception:
        return ''

class ListRouter(neutronV20.ListCommand):
    """List routers that belong to a given tenant."""

    resource = 'router'
    log = logging.getLogger(__name__ + '.ListRouter')
    _formatters = {'external_gateway_info': _format_external_gateway_info, }
    list_columns = ['id', 'name', 'external_gateway_info']
    pagination_support = True
    sorting_support = True

class ShowRouter(neutronV20.ShowCommand):
    """Show information of a given router."""

    resource = 'router'
    log = logging.getLogger(__name__ + '.ShowRouter')

class CreateRouter(neutronV20.CreateCommand):
    """Create a router for a given tenant."""

    resource = 'router'
    log = logging.getLogger(__name__ + '.CreateRouter')
    _formatters = {'external_gateway_info': _format_external_gateway_info, }

    def add_known_arguments(self, parser):
        parser.add_argument(
            '--admin-state-down',
            dest='admin_state', action='store_false',
            help=_('Set admin state up to false.'))
        parser.add_argument(
            '--admin_state_down',
            dest='admin_state', action='store_false',
            help=argparse.SUPPRESS)
        parser.add_argument(
            'name', metavar='NAME',
            help=_('Name of router to create.'))
        parser.add_argument(
            'distributed', action='store_true',
            help=_('Create a distributed router (VMware NSX plugin only).'))

    def args2body(self, parsed_args):
        body = {'router': {
            'name': parsed_args.name,
            'admin_state_up': parsed_args.admin_state, }, }
        if parsed_args.tenant_id:
            body['router'].update({'tenant_id': parsed_args.tenant_id})
        return body

class DeleteRouter(neutronV20.DeleteCommand):
    """Delete a given router."""

    log = logging.getLogger(__name__ + '.DeleteRouter')
    resource = 'router'

class UpdateRouter(neutronV20.UpdateCommand):
    """Update router's information."""

    log = logging.getLogger(__name__ + '.UpdateRouter')
    resource = 'router'

class RouterInterfaceCommand(neutronV20.NeutronCommand):
    """Based class to Add/Remove router interface."""

    api = 'network'
    resource = 'router'

    def call_api(self, neutron_client, router_id, body):
        raise NotImplementedError()

    def success_message(self, router_id, portinfo):
        raise NotImplementedError()

    def get_parser(self, prog_name):
        parser = super(RouterInterfaceCommand, self).get_parser(prog_name)
        parser.add_argument(
            'router_id', metavar='router-id',
            help=_('ID of the router.'))
        parser.add_argument(
            'interface', metavar='INTERFACE',
            help=_('The format is "SUBNET|subnet=SUBNET|port=PORT". '
            'Either a subnet or port must be specified. '
            'Both ID and name are accepted as SUBNET or PORT. '
            'Note that "subnet=" can be omitted when specifying a subnet.'))
        return parser

    def run(self, parsed_args):
        self.log.debug('run(%s)' % parsed_args)
        neutron_client = self.get_client()
        neutron_client.format = parsed_args.request_format

        if '=' in parsed_args.interface:
            resource, value = parsed_args.interface.split('=', 1)
            if resource not in ['subnet', 'port']:
                exceptions.CommandError(_('You must specify either subnet or '
                                        'port for INTERFACE parameter.'))
        else:
            resource = 'subnet'
            value = parsed_args.interface

        _router_id = neutronV20.find_resourceid_by_name_or_id(
            neutron_client, self.resource, parsed_args.router_id)

        _interface_id = neutronV20.find_resourceid_by_name_or_id(
            neutron_client, resource, value)
        body = {'%s_id' % resource: _interface_id}

        portinfo = self.call_api(neutron_client, _router_id, body)
        print(self.success_message(parsed_args.router_id, portinfo),
              file=self.app.stdout)

class AddInterfaceRouter(RouterInterfaceCommand):
    """Add an internal network interface to a router."""

    log = logging.getLogger(__name__ + '.AddInterfaceRouter')

    def call_api(self, neutron_client, router_id, body):
        return neutron_client.add_interface_router(router_id, body)

    def success_message(self, router_id, portinfo):
        return (_('Added interface %(port)s to router %(router)s.') %
                {'router': router_id, 'port': portinfo['port_id']})

class RemoveInterfaceRouter(RouterInterfaceCommand):
    """Remove an internal network interface from a router."""

    log = logging.getLogger(__name__ + '.RemoveInterfaceRouter')

    def call_api(self, neutron_client, router_id, body):
        return neutron_client.remove_interface_router(router_id, body)

    def success_message(self, router_id, portinfo):
        # portinfo is not used since it is None for router-interface-delete.
        return _('Removed interface from router %s.') % router_id

class SetGatewayRouter(neutronV20.NeutronCommand):
    """Set the external network gateway for a router."""

    log = logging.getLogger(__name__ + '.SetGatewayRouter')
    api = 'network'
    resource = 'router'

    def get_parser(self, prog_name):
        parser = super(SetGatewayRouter, self).get_parser(prog_name)
        parser.add_argument(
            'router_id', metavar='router-id',
            help=_('ID of the router.'))
        parser.add_argument(
            'external_network_id', metavar='external-network-id',
            help=_('ID of the external network for the gateway.'))
        parser.add_argument(
            '--disable-snat', action='store_true',
            help=_('Disable source NAT on the router gateway.'))
        return parser

    def run(self, parsed_args):
        self.log.debug('run(%s)' % parsed_args)
        neutron_client = self.get_client()
        neutron_client.format = parsed_args.request_format
        _router_id = neutronV20.find_resourceid_by_name_or_id(
            neutron_client, self.resource, parsed_args.router_id)
        _ext_net_id = neutronV20.find_resourceid_by_name_or_id(
            neutron_client, 'network', parsed_args.external_network_id)
        router_dict = {'network_id': _ext_net_id}
        if parsed_args.disable_snat:
            router_dict['enable_snat'] = False
        neutron_client.add_gateway_router(_router_id, router_dict)
        print(_('Set gateway for router %s') % parsed_args.router_id,
              file=self.app.stdout)

class RemoveGatewayRouter(neutronV20.NeutronCommand):
    """Remove an external network gateway from a router."""

    log = logging.getLogger(__name__ + '.RemoveGatewayRouter')
    api = 'network'
    resource = 'router'

    def get_parser(self, prog_name):
        parser = super(RemoveGatewayRouter, self).get_parser(prog_name)
        parser.add_argument(
            'router_id', metavar='router-id',
            help=_('ID of the router.'))
        return parser

    def run(self, parsed_args):
        self.log.debug('run(%s)' % parsed_args)
        neutron_client = self.get_client()
        neutron_client.format = parsed_args.request_format
        _router_id = neutronV20.find_resourceid_by_name_or_id(
            neutron_client, self.resource, parsed_args.router_id)
        neutron_client.remove_gateway_router(_router_id)
        print(_('Removed gateway from router %s') % parsed_args.router_id,
              file=self.app.stdout)
<commit_msg>Add CLI Support for DVR<commit_after># Copyright 2012 OpenStack Foundation.
# All Rights Reserved
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
#

from __future__ import print_function

import argparse
import logging

from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
from neutronclient.openstack.common.gettextutils import _

def _format_external_gateway_info(router):
    try:
        return utils.dumps(router['external_gateway_info'])
    except Exception:
        return ''

class ListRouter(neutronV20.ListCommand):
    """List routers that belong to a given tenant."""

    resource = 'router'
    log = logging.getLogger(__name__ + '.ListRouter')
    _formatters = {'external_gateway_info': _format_external_gateway_info, }
    list_columns = ['id', 'name', 'external_gateway_info', 'distributed']
    pagination_support = True
    sorting_support = True

class ShowRouter(neutronV20.ShowCommand):
    """Show information of a given router."""

    resource = 'router'
    log = logging.getLogger(__name__ + '.ShowRouter')

class CreateRouter(neutronV20.CreateCommand):
    """Create a router for a given tenant."""

    resource = 'router'
    log = logging.getLogger(__name__ + '.CreateRouter')
    _formatters = {'external_gateway_info': _format_external_gateway_info, }

    def add_known_arguments(self, parser):
        parser.add_argument(
            '--admin-state-down',
            dest='admin_state', action='store_false',
            help=_('Set admin state up to false.'))
        parser.add_argument(
            '--admin_state_down',
            dest='admin_state', action='store_false',
            help=argparse.SUPPRESS)
        parser.add_argument(
            'name', metavar='NAME',
            help=_('Name of router to create.'))
        parser.add_argument(
            'distributed', action='store_true',
            help=_('Create a distributed router.'))

    def args2body(self, parsed_args):
        body = {'router': {
            'name': parsed_args.name,
            'admin_state_up': parsed_args.admin_state, }, }
        if parsed_args.tenant_id:
            body['router'].update({'tenant_id': parsed_args.tenant_id})
        return body

class DeleteRouter(neutronV20.DeleteCommand):
    """Delete a given router."""

    log = logging.getLogger(__name__ + '.DeleteRouter')
    resource = 'router'

class UpdateRouter(neutronV20.UpdateCommand):
    """Update router's information."""

    log = logging.getLogger(__name__ + '.UpdateRouter')
    resource = 'router'

class RouterInterfaceCommand(neutronV20.NeutronCommand):
    """Based class to Add/Remove router interface."""

    api = 'network'
    resource = 'router'

    def call_api(self, neutron_client, router_id, body):
        raise NotImplementedError()

    def success_message(self, router_id, portinfo):
        raise NotImplementedError()

    def get_parser(self, prog_name):
        parser = super(RouterInterfaceCommand, self).get_parser(prog_name)
        parser.add_argument(
            'router_id', metavar='router-id',
            help=_('ID of the router.'))
        parser.add_argument(
            'interface', metavar='INTERFACE',
            help=_('The format is "SUBNET|subnet=SUBNET|port=PORT". '
            'Either a subnet or port must be specified. '
            'Both ID and name are accepted as SUBNET or PORT. '
            'Note that "subnet=" can be omitted when specifying a subnet.'))
        return parser

    def run(self, parsed_args):
        self.log.debug('run(%s)' % parsed_args)
        neutron_client = self.get_client()
        neutron_client.format = parsed_args.request_format

        if '=' in parsed_args.interface:
            resource, value = parsed_args.interface.split('=', 1)
            if resource not in ['subnet', 'port']:
                exceptions.CommandError(_('You must specify either subnet or '
                                        'port for INTERFACE parameter.'))
        else:
            resource = 'subnet'
            value = parsed_args.interface

        _router_id = neutronV20.find_resourceid_by_name_or_id(
            neutron_client, self.resource, parsed_args.router_id)

        _interface_id = neutronV20.find_resourceid_by_name_or_id(
            neutron_client, resource, value)
        body = {'%s_id' % resource: _interface_id}

        portinfo = self.call_api(neutron_client, _router_id, body)
        print(self.success_message(parsed_args.router_id, portinfo),
              file=self.app.stdout)

class AddInterfaceRouter(RouterInterfaceCommand):
    """Add an internal network interface to a router."""

    log = logging.getLogger(__name__ + '.AddInterfaceRouter')

    def call_api(self, neutron_client, router_id, body):
        return neutron_client.add_interface_router(router_id, body)

    def success_message(self, router_id, portinfo):
        return (_('Added interface %(port)s to router %(router)s.') %
                {'router': router_id, 'port': portinfo['port_id']})

class RemoveInterfaceRouter(RouterInterfaceCommand):
    """Remove an internal network interface from a router."""

    log = logging.getLogger(__name__ + '.RemoveInterfaceRouter')

    def call_api(self, neutron_client, router_id, body):
        return neutron_client.remove_interface_router(router_id, body)

    def success_message(self, router_id, portinfo):
        # portinfo is not used since it is None for router-interface-delete.
        return _('Removed interface from router %s.') % router_id

class SetGatewayRouter(neutronV20.NeutronCommand):
    """Set the external network gateway for a router."""

    log = logging.getLogger(__name__ + '.SetGatewayRouter')
    api = 'network'
    resource = 'router'

    def get_parser(self, prog_name):
        parser = super(SetGatewayRouter, self).get_parser(prog_name)
        parser.add_argument(
            'router_id', metavar='router-id',
            help=_('ID of the router.'))
        parser.add_argument(
            'external_network_id', metavar='external-network-id',
            help=_('ID of the external network for the gateway.'))
        parser.add_argument(
            '--disable-snat', action='store_true',
            help=_('Disable source NAT on the router gateway.'))
        return parser

    def run(self, parsed_args):
        self.log.debug('run(%s)' % parsed_args)
        neutron_client = self.get_client()
        neutron_client.format = parsed_args.request_format
        _router_id = neutronV20.find_resourceid_by_name_or_id(
            neutron_client, self.resource, parsed_args.router_id)
        _ext_net_id = neutronV20.find_resourceid_by_name_or_id(
            neutron_client, 'network', parsed_args.external_network_id)
        router_dict = {'network_id': _ext_net_id}
        if parsed_args.disable_snat:
            router_dict['enable_snat'] = False
        neutron_client.add_gateway_router(_router_id, router_dict)
        print(_('Set gateway for router %s') % parsed_args.router_id,
              file=self.app.stdout)

class RemoveGatewayRouter(neutronV20.NeutronCommand):
    """Remove an external network gateway from a router."""

    log = logging.getLogger(__name__ + '.RemoveGatewayRouter')
    api = 'network'
    resource = 'router'

    def get_parser(self, prog_name):
        parser = super(RemoveGatewayRouter, self).get_parser(prog_name)
        parser.add_argument(
            'router_id', metavar='router-id',
            help=_('ID of the router.'))
        return parser

    def run(self, parsed_args):
        self.log.debug('run(%s)' % parsed_args)
        neutron_client = self.get_client()
        neutron_client.format = parsed_args.request_format
        _router_id = neutronV20.find_resourceid_by_name_or_id(
            neutron_client, self.resource, parsed_args.router_id)
        neutron_client.remove_gateway_router(_router_id)
        print(_('Removed gateway from router %s') % parsed_args.router_id,
              file=self.app.stdout)
<|endoftext|>


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

#Copyright (C) 2014 by Glenn Hickey
#
#Released under the MIT license, see LICENSE.txt
import unittest
import sys
import os
import argparse
import logging
import numpy as np
import math
import copy
import scipy

from teHmm.track import TrackList, TrackData
from teHmm.trackIO import readTrackData, getMergedBedIntervals
from teHmm.common import myLog, EPSILON, initBedTool, cleanBedTool
from teHmm.common import addLoggingOptions, setLoggingFromOptions, logger
from teHmm.common import runShellCommand

def main(argv=None):
    if argv is None:
        argv = sys.argv

    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description="Produce a bed file of genome segments which are atomic"
        " elements with resepect to the hmm. ie each segment emits a single"
        " state.  Output intervals are assigned name 0 1 0 1 etc.")

    parser.add_argument("tracksInfo", help="Path of Tracks Info file "
                        "containing paths to genome annotation tracks")
    parser.add_argument("allBed", help="Bed file spanning entire genome")
    parser.add_argument("outBed", help="Output segments")
    parser.add_argument("--thresh", help="Number of tracks that can change "
                        "before a new segment formed.  Increasing this value"
                        " increases the expected lengths of output segments",
                        type=int, default=0)
    parser.add_argument("--cutTracks", help="Create a new segment if something"
                        " changes in one of these tracks (as specified by "
                        "comman-separated list), overriding --thresh options"
                        " if necessary.  For example, --cutTracks tsd,chaux"
                        " would invoke a new segment everytime the value at"
                        "either of these tracks changed", default=None)
    parser.add_argument("--comp", help="Strategy for comparing columns for the "
                        "threshold cutoff.  Options are [first, prev], where"
                        " first compares with first column of segment and "
                        "prev compares with column immediately left",
                        default="prev")
    parser.add_argument("--ignore", help="Comma-separated list of tracks to "
                        "ignore (the FASTA DNA sequence would be a good "
                        "candidate", default=None)
    parser.add_argument("--maxLen", help="Maximum length og a segment",
                        default=None)

    addLoggingOptions(parser)
    args = parser.parse_args()
    setLoggingFromOptions(args)
    tempBedToolPath = initBedTool()

    if args.comp != "first" and args.comp != "prev":
        raise RuntimeError("--comp must be either first or prev")

    # read query intervals from the bed file
    logger.info("loading training intervals from %s" % args.allBed)
    mergedIntervals = getMergedBedIntervals(args.allBed, ncol=4)
    if mergedIntervals is None or len(mergedIntervals) < 1:
        raise RuntimeError("Could not read any intervals from %s" %
                           args.allBed)

    # read the tracks, while intersecting them with the query intervals
    logger.info("loading tracks %s" % args.tracksInfo)
    trackData = TrackData()
    trackData.loadTrackData(args.tracksInfo, mergedIntervals)

    # process the --cutTracks option
    trackList = trackData.getTrackList()
    cutList = np.zeros((len(trackList)), np.int)
    if args.cutTracks is not None:
        cutNames = args.cutTracks.split(",")
        for name in cutNames:
            track = trackList.getTrackByName(name)
            if track is None:
                raise RuntimeError("cutTrack %s not found" % name)
            trackNo = track.getNumber()
            assert trackNo < len(cutList)
            cutList[trackNo] = 1
    args.cutList = cutList

    # process the --ignore option
    ignoreList = np.zeros((len(trackList)), np.int)
    if args.ignore is not None:
        ignoreNames = args.ignore.split(",")
        for name in ignoreNames:
            track = trackList.getTrackByName(name)
            if track is None:
                raise RuntimeError("ignore track %s not found" % name)
            trackNo = track.getNumber()
            assert trackNo < len(ignoreList)
            ignoreList[trackNo] = 1
            if args.cutList[trackNo] == 1:
                raise RuntimeError("Same track (%s) cant be cut and ignored" %
                                  name)
    args.ignoreList = ignoreList

    # segment the tracks
    segmentTracks(trackData, args)

    cleanBedTool(tempBedToolPath)

def segmentTracks(trackData, args):
    """ produce a segmentation of the data based on the track values. start with
    a hacky prototype..."""
    oFile = open(args.outBed, "w")
    prevMode = args.comp == "prev"

    trackTableList = trackData.getTrackTableList()
    # for every non-contiguous region
    for trackTable in trackTableList:
        start = trackTable.getStart()
        end = trackTable.getEnd()
        chrom = trackTable.getChrom()
        interval = [chrom, start, start + 1]
        intervalLen = end - start
        # scan each column (base) in region, and write new bed segment
        # if necessary (ie too much change in track values)
        count = 0
        pi = 0
        for i in xrange(1, intervalLen):
            if isNewSegment(trackTable, pi, i, args) is True:
                oFile.write("%s\t%d\t%d\t%d\n" % (chrom, interval[1], start + i,
                                                  count % 2))
                interval[1] = start + i
                interval[2] = interval[1] + 1
                count += 1
                pi = i
            if prevMode is True:
                pi = i
        # write last segment
        if interval[1] < trackTable.getEnd():
            oFile.write("%s\t%d\t%d\t%d\n" % (chrom, interval[1],
                                              trackTable.getEnd(),
                                              count % 2))

    oFile.close()

def isNewSegment(trackTable, pi, i, args):
    """ may be necessary to cythonize this down the road """
    assert i > 0
    assert i < len(trackTable)
    assert pi >= 0
    assert pi < i

    if args.maxLen is not None and i - pi >= args.maxLen:
        return True

    # faster to just call pdist(trackTable[i-1:i], 'hamming')?
    col = trackTable[i]
    prev = trackTable[pi]
    difCount = 0
    for j in xrange(len(col)):
        if args.ignoreList[j] == 0 and col[j] != prev[j]:
            difCount += 1
            # cutList track is different
            if args.cutList[j] == 1:
                return True

    return difCount > args.thresh

if __name__ == "__main__":
    sys.exit(main())
<commit_msg>fix compare<commit_after>#!/usr/bin/env python

#Copyright (C) 2014 by Glenn Hickey
#
#Released under the MIT license, see LICENSE.txt
import unittest
import sys
import os
import argparse
import logging
import numpy as np
import math
import copy
import scipy

from teHmm.track import TrackList, TrackData
from teHmm.trackIO import readTrackData, getMergedBedIntervals
from teHmm.common import myLog, EPSILON, initBedTool, cleanBedTool
from teHmm.common import addLoggingOptions, setLoggingFromOptions, logger
from teHmm.common import runShellCommand

def main(argv=None):
    if argv is None:
        argv = sys.argv

    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description="Produce a bed file of genome segments which are atomic"
        " elements with resepect to the hmm. ie each segment emits a single"
        " state.  Output intervals are assigned name 0 1 0 1 etc.")

    parser.add_argument("tracksInfo", help="Path of Tracks Info file "
                        "containing paths to genome annotation tracks")
    parser.add_argument("allBed", help="Bed file spanning entire genome")
    parser.add_argument("outBed", help="Output segments")
    parser.add_argument("--thresh", help="Number of tracks that can change "
                        "before a new segment formed.  Increasing this value"
                        " increases the expected lengths of output segments",
                        type=int, default=0)
    parser.add_argument("--cutTracks", help="Create a new segment if something"
                        " changes in one of these tracks (as specified by "
                        "comman-separated list), overriding --thresh options"
                        " if necessary.  For example, --cutTracks tsd,chaux"
                        " would invoke a new segment everytime the value at"
                        "either of these tracks changed", default=None)
    parser.add_argument("--comp", help="Strategy for comparing columns for the "
                        "threshold cutoff.  Options are [first, prev], where"
                        " first compares with first column of segment and "
                        "prev compares with column immediately left",
                        default="prev")
    parser.add_argument("--ignore", help="Comma-separated list of tracks to "
                        "ignore (the FASTA DNA sequence would be a good "
                        "candidate", default=None)
    parser.add_argument("--maxLen", help="Maximum length og a segment",
                        default=None)

    addLoggingOptions(parser)
    args = parser.parse_args()
    setLoggingFromOptions(args)
    tempBedToolPath = initBedTool()

    if args.comp != "first" and args.comp != "prev":
        raise RuntimeError("--comp must be either first or prev")

    # read query intervals from the bed file
    logger.info("loading training intervals from %s" % args.allBed)
    mergedIntervals = getMergedBedIntervals(args.allBed, ncol=4)
    if mergedIntervals is None or len(mergedIntervals) < 1:
        raise RuntimeError("Could not read any intervals from %s" %
                           args.allBed)

    # read the tracks, while intersecting them with the query intervals
    logger.info("loading tracks %s" % args.tracksInfo)
    trackData = TrackData()
    trackData.loadTrackData(args.tracksInfo, mergedIntervals)

    # process the --cutTracks option
    trackList = trackData.getTrackList()
    cutList = np.zeros((len(trackList)), np.int)
    if args.cutTracks is not None:
        cutNames = args.cutTracks.split(",")
        for name in cutNames:
            track = trackList.getTrackByName(name)
            if track is None:
                raise RuntimeError("cutTrack %s not found" % name)
            trackNo = track.getNumber()
            assert trackNo < len(cutList)
            cutList[trackNo] = 1
    args.cutList = cutList

    # process the --ignore option
    ignoreList = np.zeros((len(trackList)), np.int)
    if args.ignore is not None:
        ignoreNames = args.ignore.split(",")
        for name in ignoreNames:
            track = trackList.getTrackByName(name)
            if track is None:
                raise RuntimeError("ignore track %s not found" % name)
            trackNo = track.getNumber()
            assert trackNo < len(ignoreList)
            ignoreList[trackNo] = 1
            if args.cutList[trackNo] == 1:
                raise RuntimeError("Same track (%s) cant be cut and ignored" %
                                  name)
    args.ignoreList = ignoreList

    # segment the tracks
    segmentTracks(trackData, args)

    cleanBedTool(tempBedToolPath)

def segmentTracks(trackData, args):
    """ produce a segmentation of the data based on the track values. start with
    a hacky prototype..."""
    oFile = open(args.outBed, "w")
    prevMode = args.comp == "prev"

    trackTableList = trackData.getTrackTableList()
    # for every non-contiguous region
    for trackTable in trackTableList:
        start = trackTable.getStart()
        end = trackTable.getEnd()
        chrom = trackTable.getChrom()
        interval = [chrom, start, start + 1]
        intervalLen = end - start
        # scan each column (base) in region, and write new bed segment
        # if necessary (ie too much change in track values)
        count = 0
        pi = 0
        for i in xrange(1, intervalLen):
            if isNewSegment(trackTable, pi, i, args) is True:
                oFile.write("%s\t%d\t%d\t%d\n" % (chrom, interval[1], start + i,
                                                  count % 2))
                interval[1] = start + i
                interval[2] = interval[1] + 1
                count += 1
                pi = i
            if prevMode is True:
                pi = i
        # write last segment
        if interval[1] < trackTable.getEnd():
            oFile.write("%s\t%d\t%d\t%d\n" % (chrom, interval[1],
                                              trackTable.getEnd(),
                                              count % 2))

    oFile.close()

def isNewSegment(trackTable, pi, i, args):
    """ may be necessary to cythonize this down the road """
    assert i > 0
    assert i < len(trackTable)
    assert pi >= 0
    assert pi < i

    curLength = i - pi
    if args.maxLen is not None and curLength >= args.maxLen:
        return True

    # faster to just call pdist(trackTable[i-1:i], 'hamming')?
    col = trackTable[i]
    prev = trackTable[pi]
    difCount = 0
    for j in xrange(len(col)):
        if args.ignoreList[j] == 0 and col[j] != prev[j]:
            difCount += 1
            # cutList track is different
            if args.cutList[j] == 1:
                return True

    return difCount > args.thresh

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