intern.service.boss.v1.volume module
# Copyright 2016 The Johns Hopkins University Applied Physics Laboratory
#
# 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 intern.service.boss import BaseVersion
from intern.service.boss.v1 import BOSS_API_VERSION
from intern.resource.boss.resource import *
from intern.utils.parallel import *
from requests import HTTPError
import blosc
import numpy as np
class VolumeService_1(BaseVersion):
def __init__(self):
BaseVersion.__init__(self)
@property
def version(self):
"""Return the API Version for this implementation
"""
return BOSS_API_VERSION
def get_bit_width(self, resource):
"""Method to return the bit width for blosc based on the Resource"""
datatype = resource.datatype
if "uint" in datatype:
bit_width = int(datatype.split("uint")[1])
else:
raise ValueError("Unsupported datatype: {}".format(datatype))
return bit_width
def create_cutout(
self, resource, resolution, x_range, y_range, z_range, time_range, numpyVolume,
url_prefix, auth, session, send_opts):
"""Upload a cutout to the Boss data store.
Args:
resource (intern.resource.resource.Resource): Resource compatible with cutout operations.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (optional [list[int]]): time range such as [30, 40] which means t>=30 and t<40.
numpyVolume (numpy.array): A 3D or 4D (time) numpy matrix in (time)ZYX order.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
"""
compressed = blosc.compress(numpyVolume, typesize=self.get_bit_width(resource))
if numpyVolume.ndim == 3:
# Can't have time
if time_range is not None:
raise ValueError(
"You must provide a 4D matrix if specifying a time range")
elif numpyVolume.ndim == 4:
# must have time
if time_range is None:
raise ValueError(
"You must specifying a time range if providing a 4D matrix")
else:
raise ValueError(
"Invalid data format. Only 3D or 4D cutouts are supported. " +
"Number of dimensions: {}".format(numpyVolume.ndim)
)
req = self.get_cutout_request(
resource, 'POST', 'application/blosc',
url_prefix, auth,
resolution, x_range, y_range, z_range, time_range, numpyVolume=compressed)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 201:
return
msg = ('Create cutout failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def get_cutout(
self, resource, resolution, x_range, y_range, z_range, time_range, id_list,
url_prefix, auth, session, send_opts
):
"""
Upload a cutout to the Boss data store.
Args:
resource (intern.resource.resource.Resource): Resource compatible
with cutout operations
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range ([list[int]]|None): time range such as [30, 40] which means t>=30 and t<40.
id_list (list[int]): list of object ids to filter the cutout by.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(numpy.array): A 3D or 4D numpy matrix in ZXY(time) order.
Raises:
requests.HTTPError
"""
# Check to see if this volume is larger than 1GB. If so, chunk it into
# several smaller bites:
if (
(x_range[1] - x_range[0]) *
(y_range[1] - y_range[0]) *
(z_range[1] - z_range[0])
) > 1024*1024*32*2:
blocks = block_compute(
x_range[0], x_range[1],
y_range[0], y_range[1],
z_range[0], z_range[1],
block_size=(1024, 1024, 32)
)
result = np.ndarray((
z_range[1] - z_range[0],
y_range[1] - y_range[0],
x_range[1] - x_range[0]
))
for b in blocks:
_data = self.get_cutout(
resource, resolution, b[0], b[1], b[2],
time_range, id_list, url_prefix, auth, session, send_opts
)
result[
b[2][0] - z_range[0] : b[2][1] - z_range[0],
b[1][0] - y_range[0] : b[1][1] - y_range[0],
b[0][0] - x_range[0] : b[0][1] - x_range[0]
] = _data
return result
req = self.get_cutout_request(
resource, 'GET', 'application/blosc',
url_prefix, auth,
resolution, x_range, y_range, z_range, time_range,
id_list=id_list
)
prep = session.prepare_request(req)
# Hack in Accept header for now.
prep.headers['Accept'] = 'application/blosc'
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
raw_data = blosc.decompress(resp.content)
data_mat = np.fromstring(raw_data, dtype=resource.datatype)
if time_range:
# Reshape including time
return np.reshape(data_mat,
(time_range[1] - time_range[0],
z_range[1] - z_range[0],
y_range[1] - y_range[0],
x_range[1] - x_range[0]),
order='C')
else:
# Reshape without including time
return np.reshape(data_mat,
(z_range[1] - z_range[0],
y_range[1] - y_range[0],
x_range[1] - x_range[0]),
order='C')
msg = ('Get cutout failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def reserve_ids(
self, resource, num_ids,
url_prefix, auth, session, send_opts):
"""Reserve a block of unique, sequential ids for annotations.
Args:
resource (intern.resource.Resource): Resource should be an annotation channel.
num_ids (int): Number of ids to reserve.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(int): First id reserved.
Raises:
(TypeError): resource is not a channel or not an annotation channel.
"""
if not isinstance(resource, ChannelResource):
raise TypeError('resource must be ChannelResource')
if resource.type != 'annotation':
raise TypeError('Channel is not an annotation channel')
req = self.get_reserve_request(
resource, 'GET', 'application/json', url_prefix, auth, num_ids)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
json_data = resp.json()
return int(json_data['start_id'])
msg = ('Reserve ids failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def get_bounding_box(
self, resource, resolution, _id, bb_type,
url_prefix, auth, session, send_opts):
"""Get bounding box containing object specified by id.
Currently only supports 'loose' bounding boxes. The bounding box
returned is cuboid aligned.
Args:
resource (intern.resource.Resource): Resource compatible with annotation operations.
resolution (int): 0 indicates native resolution.
_id (int): Id of object of interest.
bb_type (string): Defaults to 'loose'.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(dict): {'x_range': [0, 10], 'y_range': [0, 10], 'z_range': [0, 10], 't_range': [0, 10]}
Raises:
requests.HTTPError
TypeError: if resource is not an annotation channel.
"""
if not isinstance(resource, ChannelResource):
raise TypeError('resource must be ChannelResource')
if resource.type != 'annotation':
raise TypeError('Channel is not an annotation channel')
req = self.get_bounding_box_request(
resource, 'GET', 'application/json', url_prefix, auth, resolution,
_id, bb_type)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
json_data = resp.json()
return json_data
msg = ('Get bounding box failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def get_ids_in_region(
self, resource, resolution, x_range, y_range, z_range, time_range,
url_prefix, auth, session, send_opts):
"""Get all ids in the region defined by x_range, y_range, z_range.
Args:
resource (intern.resource.Resource): An annotation channel.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (list[int]]): time range such as [30, 40] which means t>=30 and t<40.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(list[int]): Example: [1, 2, 25].
Raises:
requests.HTTPError
TypeError: if resource is not an annotation channel.
"""
if not isinstance(resource, ChannelResource):
raise TypeError('resource must be ChannelResource')
if resource.type != 'annotation':
raise TypeError('Channel is not an annotation channel')
req = self.get_ids_request(
resource, 'GET', 'application/json', url_prefix, auth,
resolution, x_range, y_range, z_range, time_range)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
json_data = resp.json()
id_str_list = json_data['ids']
id_int_list = [int(i) for i in id_str_list]
return id_int_list
msg = ('Get bounding box failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
Module variables
var BOSS_API_VERSION
Classes
class VolumeService_1
class VolumeService_1(BaseVersion):
def __init__(self):
BaseVersion.__init__(self)
@property
def version(self):
"""Return the API Version for this implementation
"""
return BOSS_API_VERSION
def get_bit_width(self, resource):
"""Method to return the bit width for blosc based on the Resource"""
datatype = resource.datatype
if "uint" in datatype:
bit_width = int(datatype.split("uint")[1])
else:
raise ValueError("Unsupported datatype: {}".format(datatype))
return bit_width
def create_cutout(
self, resource, resolution, x_range, y_range, z_range, time_range, numpyVolume,
url_prefix, auth, session, send_opts):
"""Upload a cutout to the Boss data store.
Args:
resource (intern.resource.resource.Resource): Resource compatible with cutout operations.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (optional [list[int]]): time range such as [30, 40] which means t>=30 and t<40.
numpyVolume (numpy.array): A 3D or 4D (time) numpy matrix in (time)ZYX order.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
"""
compressed = blosc.compress(numpyVolume, typesize=self.get_bit_width(resource))
if numpyVolume.ndim == 3:
# Can't have time
if time_range is not None:
raise ValueError(
"You must provide a 4D matrix if specifying a time range")
elif numpyVolume.ndim == 4:
# must have time
if time_range is None:
raise ValueError(
"You must specifying a time range if providing a 4D matrix")
else:
raise ValueError(
"Invalid data format. Only 3D or 4D cutouts are supported. " +
"Number of dimensions: {}".format(numpyVolume.ndim)
)
req = self.get_cutout_request(
resource, 'POST', 'application/blosc',
url_prefix, auth,
resolution, x_range, y_range, z_range, time_range, numpyVolume=compressed)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 201:
return
msg = ('Create cutout failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def get_cutout(
self, resource, resolution, x_range, y_range, z_range, time_range, id_list,
url_prefix, auth, session, send_opts
):
"""
Upload a cutout to the Boss data store.
Args:
resource (intern.resource.resource.Resource): Resource compatible
with cutout operations
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range ([list[int]]|None): time range such as [30, 40] which means t>=30 and t<40.
id_list (list[int]): list of object ids to filter the cutout by.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(numpy.array): A 3D or 4D numpy matrix in ZXY(time) order.
Raises:
requests.HTTPError
"""
# Check to see if this volume is larger than 1GB. If so, chunk it into
# several smaller bites:
if (
(x_range[1] - x_range[0]) *
(y_range[1] - y_range[0]) *
(z_range[1] - z_range[0])
) > 1024*1024*32*2:
blocks = block_compute(
x_range[0], x_range[1],
y_range[0], y_range[1],
z_range[0], z_range[1],
block_size=(1024, 1024, 32)
)
result = np.ndarray((
z_range[1] - z_range[0],
y_range[1] - y_range[0],
x_range[1] - x_range[0]
))
for b in blocks:
_data = self.get_cutout(
resource, resolution, b[0], b[1], b[2],
time_range, id_list, url_prefix, auth, session, send_opts
)
result[
b[2][0] - z_range[0] : b[2][1] - z_range[0],
b[1][0] - y_range[0] : b[1][1] - y_range[0],
b[0][0] - x_range[0] : b[0][1] - x_range[0]
] = _data
return result
req = self.get_cutout_request(
resource, 'GET', 'application/blosc',
url_prefix, auth,
resolution, x_range, y_range, z_range, time_range,
id_list=id_list
)
prep = session.prepare_request(req)
# Hack in Accept header for now.
prep.headers['Accept'] = 'application/blosc'
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
raw_data = blosc.decompress(resp.content)
data_mat = np.fromstring(raw_data, dtype=resource.datatype)
if time_range:
# Reshape including time
return np.reshape(data_mat,
(time_range[1] - time_range[0],
z_range[1] - z_range[0],
y_range[1] - y_range[0],
x_range[1] - x_range[0]),
order='C')
else:
# Reshape without including time
return np.reshape(data_mat,
(z_range[1] - z_range[0],
y_range[1] - y_range[0],
x_range[1] - x_range[0]),
order='C')
msg = ('Get cutout failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def reserve_ids(
self, resource, num_ids,
url_prefix, auth, session, send_opts):
"""Reserve a block of unique, sequential ids for annotations.
Args:
resource (intern.resource.Resource): Resource should be an annotation channel.
num_ids (int): Number of ids to reserve.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(int): First id reserved.
Raises:
(TypeError): resource is not a channel or not an annotation channel.
"""
if not isinstance(resource, ChannelResource):
raise TypeError('resource must be ChannelResource')
if resource.type != 'annotation':
raise TypeError('Channel is not an annotation channel')
req = self.get_reserve_request(
resource, 'GET', 'application/json', url_prefix, auth, num_ids)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
json_data = resp.json()
return int(json_data['start_id'])
msg = ('Reserve ids failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def get_bounding_box(
self, resource, resolution, _id, bb_type,
url_prefix, auth, session, send_opts):
"""Get bounding box containing object specified by id.
Currently only supports 'loose' bounding boxes. The bounding box
returned is cuboid aligned.
Args:
resource (intern.resource.Resource): Resource compatible with annotation operations.
resolution (int): 0 indicates native resolution.
_id (int): Id of object of interest.
bb_type (string): Defaults to 'loose'.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(dict): {'x_range': [0, 10], 'y_range': [0, 10], 'z_range': [0, 10], 't_range': [0, 10]}
Raises:
requests.HTTPError
TypeError: if resource is not an annotation channel.
"""
if not isinstance(resource, ChannelResource):
raise TypeError('resource must be ChannelResource')
if resource.type != 'annotation':
raise TypeError('Channel is not an annotation channel')
req = self.get_bounding_box_request(
resource, 'GET', 'application/json', url_prefix, auth, resolution,
_id, bb_type)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
json_data = resp.json()
return json_data
msg = ('Get bounding box failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def get_ids_in_region(
self, resource, resolution, x_range, y_range, z_range, time_range,
url_prefix, auth, session, send_opts):
"""Get all ids in the region defined by x_range, y_range, z_range.
Args:
resource (intern.resource.Resource): An annotation channel.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (list[int]]): time range such as [30, 40] which means t>=30 and t<40.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(list[int]): Example: [1, 2, 25].
Raises:
requests.HTTPError
TypeError: if resource is not an annotation channel.
"""
if not isinstance(resource, ChannelResource):
raise TypeError('resource must be ChannelResource')
if resource.type != 'annotation':
raise TypeError('Channel is not an annotation channel')
req = self.get_ids_request(
resource, 'GET', 'application/json', url_prefix, auth,
resolution, x_range, y_range, z_range, time_range)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
json_data = resp.json()
id_str_list = json_data['ids']
id_int_list = [int(i) for i in id_str_list]
return id_int_list
msg = ('Get bounding box failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
Ancestors (in MRO)
- VolumeService_1
- intern.service.boss.baseversion.BaseVersion
- __builtin__.object
Instance variables
var version
Return the API Version for this implementation
Methods
def __init__(
self)
def __init__(self):
BaseVersion.__init__(self)
def build_cutout_url(
self, resource, url_prefix, resolution, x_range, y_range, z_range, time_range=None, id_list=[])
Build the url to access the cutout function of the Boss' volume service.
Args:
url_prefix (string): Do not end with a slash. Example of expected value: https://api.theboss.io
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (optional [list[int]]): time range such as [30, 40] which means t>=30 and t<40.
id_list (optional [list[int]]): list of object ids to filter the cutout by.
Returns
(string): Full URL to access API.
Raises
(RuntimeError): if *_range invalid.
def build_cutout_url(
self, resource, url_prefix, resolution, x_range, y_range, z_range, time_range=None, id_list=[]):
"""Build the url to access the cutout function of the Boss' volume service.
Args:
url_prefix (string): Do not end with a slash. Example of expected value: https://api.theboss.io
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (optional [list[int]]): time range such as [30, 40] which means t>=30 and t<40.
id_list (optional [list[int]]): list of object ids to filter the cutout by.
Returns:
(string): Full URL to access API.
Raises:
(RuntimeError): if *_range invalid.
"""
baseUrl = self.build_url(resource, url_prefix, 'cutout', req_type='cutout')
x_rng_lst = self.convert_int_list_range_to_str(x_range)
y_rng_lst = self.convert_int_list_range_to_str(y_range)
z_rng_lst = self.convert_int_list_range_to_str(z_range)
urlWithParams = (
baseUrl + '/' + str(resolution) + '/' + x_rng_lst + '/' + y_rng_lst +
'/' + z_rng_lst + '/')
if time_range is not None:
t_rng_lst = self.convert_int_list_range_to_str(time_range)
urlWithParams += t_rng_lst + '/'
if len(id_list) > 0:
urlWithParams += '?filter=' + self.convert_int_list_to_comma_sep_str(id_list)
return urlWithParams
def build_ids_url(
self, resource, url_prefix, resolution, x_range, y_range, z_range, time_range=None)
Build the url to access the ids function of the Boss' volume service.
 Example of expected value: https://api.theboss.io
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (optional [list[int]]): time range such as [30, 40] which means t>=30 and t<40.
Returns
(string): Full URL to access API.
Raises
(RuntimeError): if *_range invalid.
def build_ids_url(
self, resource, url_prefix, resolution,
x_range, y_range, z_range, time_range=None):
"""Build the url to access the ids function of the Boss' volume service.
 Example of expected value: https://api.theboss.io
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (optional [list[int]]): time range such as [30, 40] which means t>=30 and t<40.
Returns:
(string): Full URL to access API.
Raises:
(RuntimeError): if *_range invalid.
"""
base_url = self.build_url(resource, url_prefix, 'ids', req_type='cutout')
x_rng_lst = self.convert_int_list_range_to_str(x_range)
y_rng_lst = self.convert_int_list_range_to_str(y_range)
z_rng_lst = self.convert_int_list_range_to_str(z_range)
url_with_params = (
base_url + '/' + str(resolution) + '/' + x_rng_lst + '/' + y_rng_lst +
'/' + z_rng_lst + '/')
if time_range is not None:
t_rng_lst = self.convert_int_list_range_to_str(time_range)
url_with_params += t_rng_lst + '/'
return url_with_params
def build_metadata_url(
self, resource, url_prefix, key, value=None)
Build the url to access the Boss' metadata service.
Args:
url_prefix (string): Do not end with a slash. Example of expected value: https://api.theboss.io
key (string): Key to get/create/update/delete.
value (string): Value to assign to key or None.
Returns
(string): Full URL to access API.
def build_metadata_url(self, resource, url_prefix, key, value=None):
"""Build the url to access the Boss' metadata service.
Args:
url_prefix (string): Do not end with a slash. Example of expected value: https://api.theboss.io
key (string): Key to get/create/update/delete.
value (string): Value to assign to key or None.
Returns:
(string): Full URL to access API.
"""
if url_prefix is None or url_prefix == '':
raise RuntimeError('url_prefix required.')
suffix = resource.get_meta_route()
urlNoParams = (url_prefix + '/' + self.version + '/meta/' + suffix)
if key is None:
return urlNoParams
urlWithKey = urlNoParams + '/?key=' + key
if value is None:
return urlWithKey
return urlWithKey + '&value=' + str(value)
def build_url(
self, resource, url_prefix, service, req_type='normal')
Build the url to access the Boss' project service.
Args:
url_prefix (string): Do not end with a slash. Example of expected value: https://api.theboss.io
service (string): Name of service to access, such as collection, meta, coord, etc.
req_type (optional[string]): Valid values ['normal', 'list', 'cutout']. Defaults to 'normal'.
Returns
(string): Full URL to access API.
Raises
(RuntimeError): if invalid req_type given or url_prefix not given.
def build_url(self, resource, url_prefix, service, req_type='normal'):
"""Build the url to access the Boss' project service.
Args:
url_prefix (string): Do not end with a slash. Example of expected value: https://api.theboss.io
service (string): Name of service to access, such as collection, meta, coord, etc.
req_type (optional[string]): Valid values ['normal', 'list', 'cutout']. Defaults to 'normal'.
Returns:
(string): Full URL to access API.
Raises:
(RuntimeError): if invalid req_type given or url_prefix not given.
"""
if url_prefix is None or url_prefix == '':
raise RuntimeError('url_prefix required.')
if req_type == 'normal':
suffix = resource.get_route()
elif req_type == 'list':
# No suffix required for a list request.
suffix = resource.get_list_route()
elif req_type == 'cutout':
suffix = resource.get_cutout_route()
else:
raise RuntimeError('Invalid request type: {}'.format(req_type))
url = (url_prefix + '/' + self.version + '/' + service + '/' + suffix)
return url
def convert_int_list_range_to_str(
self, int_list)
Convert range in list of two ints to string representation.
Returned string can then be placed in URL as a query parameter.
Args:
int_list (list[int]): range such as [10, 20] which means x>=10 and x<20.
Returns
(string): [10, 20] => '10:20'
Raises
(RuntimeError): if given invalid range.
def convert_int_list_range_to_str(self, int_list):
"""Convert range in list of two ints to string representation.
Returned string can then be placed in URL as a query parameter.
Args:
int_list (list[int]): range such as [10, 20] which means x>=10 and x<20.
Returns:
(string): [10, 20] => '10:20'
Raises:
(RuntimeError): if given invalid range.
"""
if len(int_list) != 2:
raise RuntimeError('int_list must contain exactly two values.')
if int_list[0] > int_list[1]:
raise RuntimeError('Invalid range: int_list[0] > int_list[1].')
return '{}:{}'.format(int_list[0], int_list[1])
def convert_int_list_to_comma_sep_str(
self, int_list)
Convert list of ints to comma separated stringj.
Args:
int_list (list[int]): list of ints.
Returns
(string): Example: [1, 7, 9] => '1, 7, 9'
def convert_int_list_to_comma_sep_str(self, int_list):
"""Convert list of ints to comma separated stringj.
Args:
int_list (list[int]): list of ints.
Returns:
(string): Example: [1, 7, 9] => '1, 7, 9'
"""
if len(int_list) == 1:
return str(int_list[0])
str_list = []
for n in int_list:
str_list.append(str(n))
return (',').join(str_list)
def create_cutout(
self, resource, resolution, x_range, y_range, z_range, time_range, numpyVolume, url_prefix, auth, session, send_opts)
Upload a cutout to the Boss data store.
Args:
resource (intern.resource.resource.Resource): Resource compatible with cutout operations.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (optional [list[int]]): time range such as [30, 40] which means t>=30 and t<40.
numpyVolume (numpy.array): A 3D or 4D (time) numpy matrix in (time)ZYX order.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
def create_cutout(
self, resource, resolution, x_range, y_range, z_range, time_range, numpyVolume,
url_prefix, auth, session, send_opts):
"""Upload a cutout to the Boss data store.
Args:
resource (intern.resource.resource.Resource): Resource compatible with cutout operations.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (optional [list[int]]): time range such as [30, 40] which means t>=30 and t<40.
numpyVolume (numpy.array): A 3D or 4D (time) numpy matrix in (time)ZYX order.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
"""
compressed = blosc.compress(numpyVolume, typesize=self.get_bit_width(resource))
if numpyVolume.ndim == 3:
# Can't have time
if time_range is not None:
raise ValueError(
"You must provide a 4D matrix if specifying a time range")
elif numpyVolume.ndim == 4:
# must have time
if time_range is None:
raise ValueError(
"You must specifying a time range if providing a 4D matrix")
else:
raise ValueError(
"Invalid data format. Only 3D or 4D cutouts are supported. " +
"Number of dimensions: {}".format(numpyVolume.ndim)
)
req = self.get_cutout_request(
resource, 'POST', 'application/blosc',
url_prefix, auth,
resolution, x_range, y_range, z_range, time_range, numpyVolume=compressed)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 201:
return
msg = ('Create cutout failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def get_bit_width(
self, resource)
Method to return the bit width for blosc based on the Resource
def get_bit_width(self, resource):
"""Method to return the bit width for blosc based on the Resource"""
datatype = resource.datatype
if "uint" in datatype:
bit_width = int(datatype.split("uint")[1])
else:
raise ValueError("Unsupported datatype: {}".format(datatype))
return bit_width
def get_bounding_box(
self, resource, resolution, _id, bb_type, url_prefix, auth, session, send_opts)
Get bounding box containing object specified by id.
Currently only supports 'loose' bounding boxes. The bounding box
returned is cuboid aligned.
Args:
resource (intern.resource.Resource): Resource compatible with annotation operations.
resolution (int): 0 indicates native resolution.
_id (int): Id of object of interest.
bb_type (string): Defaults to 'loose'.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns
(dict): {'x_range': [0, 10], 'y_range': [0, 10], 'z_range': [0, 10], 't_range': [0, 10]}
Raises
requests.HTTPError
TypeError: if resource is not an annotation channel.
def get_bounding_box(
self, resource, resolution, _id, bb_type,
url_prefix, auth, session, send_opts):
"""Get bounding box containing object specified by id.
Currently only supports 'loose' bounding boxes. The bounding box
returned is cuboid aligned.
Args:
resource (intern.resource.Resource): Resource compatible with annotation operations.
resolution (int): 0 indicates native resolution.
_id (int): Id of object of interest.
bb_type (string): Defaults to 'loose'.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(dict): {'x_range': [0, 10], 'y_range': [0, 10], 'z_range': [0, 10], 't_range': [0, 10]}
Raises:
requests.HTTPError
TypeError: if resource is not an annotation channel.
"""
if not isinstance(resource, ChannelResource):
raise TypeError('resource must be ChannelResource')
if resource.type != 'annotation':
raise TypeError('Channel is not an annotation channel')
req = self.get_bounding_box_request(
resource, 'GET', 'application/json', url_prefix, auth, resolution,
_id, bb_type)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
json_data = resp.json()
return json_data
msg = ('Get bounding box failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def get_bounding_box_request(
self, resource, method, content, url_prefix, token, resolution, id, bb_type)
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
resolution (int): 0 = default resolution.
id (int): Annotation object id.
bb_type (string): 'loose' | 'tight'.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_bounding_box_request(
self, resource, method, content, url_prefix, token, resolution,
id, bb_type):
"""
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
resolution (int): 0 = default resolution.
id (int): Annotation object id.
bb_type (string): 'loose' | 'tight'.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
if url_prefix is None or url_prefix == '':
raise RuntimeError('url_prefix required.')
url = (url_prefix + '/' + self.version + '/boundingbox/' +
resource.get_cutout_route() + '/{}/{}/?type={}'.format(
resolution, id, bb_type))
headers = self.get_headers(content, token)
return Request(method, url, headers=headers)
def get_cutout(
self, resource, resolution, x_range, y_range, z_range, time_range, id_list, url_prefix, auth, session, send_opts)
Upload a cutout to the Boss data store.
Args:
resource (intern.resource.resource.Resource): Resource compatible
with cutout operations
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range ([list[int]]|None): time range such as [30, 40] which means t>=30 and t<40.
id_list (list[int]): list of object ids to filter the cutout by.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns
(numpy.array): A 3D or 4D numpy matrix in ZXY(time) order.
Raises
requests.HTTPError
def get_cutout(
self, resource, resolution, x_range, y_range, z_range, time_range, id_list,
url_prefix, auth, session, send_opts
):
"""
Upload a cutout to the Boss data store.
Args:
resource (intern.resource.resource.Resource): Resource compatible
with cutout operations
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range ([list[int]]|None): time range such as [30, 40] which means t>=30 and t<40.
id_list (list[int]): list of object ids to filter the cutout by.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(numpy.array): A 3D or 4D numpy matrix in ZXY(time) order.
Raises:
requests.HTTPError
"""
# Check to see if this volume is larger than 1GB. If so, chunk it into
# several smaller bites:
if (
(x_range[1] - x_range[0]) *
(y_range[1] - y_range[0]) *
(z_range[1] - z_range[0])
) > 1024*1024*32*2:
blocks = block_compute(
x_range[0], x_range[1],
y_range[0], y_range[1],
z_range[0], z_range[1],
block_size=(1024, 1024, 32)
)
result = np.ndarray((
z_range[1] - z_range[0],
y_range[1] - y_range[0],
x_range[1] - x_range[0]
))
for b in blocks:
_data = self.get_cutout(
resource, resolution, b[0], b[1], b[2],
time_range, id_list, url_prefix, auth, session, send_opts
)
result[
b[2][0] - z_range[0] : b[2][1] - z_range[0],
b[1][0] - y_range[0] : b[1][1] - y_range[0],
b[0][0] - x_range[0] : b[0][1] - x_range[0]
] = _data
return result
req = self.get_cutout_request(
resource, 'GET', 'application/blosc',
url_prefix, auth,
resolution, x_range, y_range, z_range, time_range,
id_list=id_list
)
prep = session.prepare_request(req)
# Hack in Accept header for now.
prep.headers['Accept'] = 'application/blosc'
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
raw_data = blosc.decompress(resp.content)
data_mat = np.fromstring(raw_data, dtype=resource.datatype)
if time_range:
# Reshape including time
return np.reshape(data_mat,
(time_range[1] - time_range[0],
z_range[1] - z_range[0],
y_range[1] - y_range[0],
x_range[1] - x_range[0]),
order='C')
else:
# Reshape without including time
return np.reshape(data_mat,
(z_range[1] - z_range[0],
y_range[1] - y_range[0],
x_range[1] - x_range[0]),
order='C')
msg = ('Get cutout failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def get_cutout_request(
self, resource, method, content, url_prefix, token, resolution, x_range, y_range, z_range, time_range, numpyVolume=None, id_list=[])
Create a request for working with cutouts (part of the Boss' volume service).
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (list[int]): time range such as [30, 40] which means t>=30 and t<40.
numpyVolume (optional numpy array): The data volume encoded in a numpy array.
id_list (optional [list[int]]): list of object ids to filter the cutout by.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_cutout_request(
self, resource, method, content, url_prefix, token,
resolution, x_range, y_range, z_range, time_range, numpyVolume=None, id_list=[]):
"""Create a request for working with cutouts (part of the Boss' volume service).
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (list[int]): time range such as [30, 40] which means t>=30 and t<40.
numpyVolume (optional numpy array): The data volume encoded in a numpy array.
id_list (optional [list[int]]): list of object ids to filter the cutout by.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
url = self.build_cutout_url(
resource, url_prefix, resolution, x_range, y_range, z_range, time_range, id_list)
headers = self.get_headers(content, token)
return Request(method, url, headers = headers, data = numpyVolume)
def get_group_maintainers_request(
self, method, content, url_prefix, token, group_name, user_name=None)
Get a request object for working with group maintainers.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
group_name (string): Name of group.
user_name (optional[string]): Provide a user name if not doing a list operation. Defaults to None.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_group_maintainers_request(
self, method, content, url_prefix, token, group_name, user_name=None):
"""Get a request object for working with group maintainers.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
group_name (string): Name of group.
user_name (optional[string]): Provide a user name if not doing a list operation. Defaults to None.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
if url_prefix is None or url_prefix == '':
raise RuntimeError('url_prefix required.')
url = url_prefix + '/' + self.version + '/groups/' + group_name + '/maintainers/'
if user_name is not None:
url += user_name
headers = self.get_headers(content, token)
return Request(method, url, headers = headers)
def get_group_members_request(
self, method, content, url_prefix, token, group_name, user_name=None)
Get a request object for working with group membership.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
group_name (string): Name of group.
user_name (optional[string]): Provide a user name if not doing a list operation. Defaults to None.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_group_members_request(
self, method, content, url_prefix, token, group_name, user_name=None):
"""Get a request object for working with group membership.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
group_name (string): Name of group.
user_name (optional[string]): Provide a user name if not doing a list operation. Defaults to None.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
if url_prefix is None or url_prefix == '':
raise RuntimeError('url_prefix required.')
url = url_prefix + '/' + self.version + '/groups/' + group_name + '/members/'
if user_name is not None:
url += user_name
headers = self.get_headers(content, token)
return Request(method, url, headers = headers)
def get_group_request(
self, method, content, url_prefix, token, name=None)
Get a request for getting group information.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
name (optional[string|None]): Name of group. Defaults to None.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_group_request(self, method, content, url_prefix, token, name=None):
"""Get a request for getting group information.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
name (optional[string|None]): Name of group. Defaults to None.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
if url_prefix is None or url_prefix == '':
raise RuntimeError('url_prefix required.')
url = url_prefix + '/' + self.version + '/groups/'
if name is not None:
url += name + '/'
headers = self.get_headers(content, token)
return Request(method, url, headers = headers)
def get_headers(
self, content_type, token)
Get headers to place in Request object.
The auth token is added to the header for authenthication and
authorization.
Args:
content_type (string): HTTP content type of request.
token (string): Django Rest Framework token.
Returns
(dictionary): Use as headers argument to the Request object.
def get_headers(self, content_type, token):
"""Get headers to place in Request object.
The auth token is added to the header for authenthication and
authorization.
Args:
content_type (string): HTTP content type of request.
token (string): Django Rest Framework token.
Returns:
(dictionary): Use as headers argument to the Request object.
"""
return {
'Authorization': 'Token ' + token,
'Content-Type': content_type
}
def get_ids_in_region(
self, resource, resolution, x_range, y_range, z_range, time_range, url_prefix, auth, session, send_opts)
Get all ids in the region defined by x_range, y_range, z_range.
Args:
resource (intern.resource.Resource): An annotation channel.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (list[int]]): time range such as [30, 40] which means t>=30 and t<40.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns
(list[int]): Example: [1, 2, 25].
Raises
requests.HTTPError
TypeError: if resource is not an annotation channel.
def get_ids_in_region(
self, resource, resolution, x_range, y_range, z_range, time_range,
url_prefix, auth, session, send_opts):
"""Get all ids in the region defined by x_range, y_range, z_range.
Args:
resource (intern.resource.Resource): An annotation channel.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (list[int]]): time range such as [30, 40] which means t>=30 and t<40.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(list[int]): Example: [1, 2, 25].
Raises:
requests.HTTPError
TypeError: if resource is not an annotation channel.
"""
if not isinstance(resource, ChannelResource):
raise TypeError('resource must be ChannelResource')
if resource.type != 'annotation':
raise TypeError('Channel is not an annotation channel')
req = self.get_ids_request(
resource, 'GET', 'application/json', url_prefix, auth,
resolution, x_range, y_range, z_range, time_range)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
json_data = resp.json()
id_str_list = json_data['ids']
id_int_list = [int(i) for i in id_str_list]
return id_int_list
msg = ('Get bounding box failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)
def get_ids_request(
self, resource, method, content, url_prefix, token, resolution, x_range, y_range, z_range, time_range)
Create a request for getting ids in a region (part of the Boss' volume service).
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (list[int]): time range such as [30, 40] which means t>=30 and t<40.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_ids_request(
self, resource, method, content, url_prefix, token,
resolution, x_range, y_range, z_range, time_range):
"""Create a request for getting ids in a region (part of the Boss' volume service).
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
resolution (int): 0 indicates native resolution.
x_range (list[int]): x range such as [10, 20] which means x>=10 and x<20.
y_range (list[int]): y range such as [10, 20] which means y>=10 and y<20.
z_range (list[int]): z range such as [10, 20] which means z>=10 and z<20.
time_range (list[int]): time range such as [30, 40] which means t>=30 and t<40.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
url = self.build_ids_url(
resource, url_prefix, resolution, x_range, y_range, z_range, time_range)
headers = self.get_headers(content, token)
return Request(method, url, headers=headers)
def get_metadata_request(
self, resource, method, content, url_prefix, token, key=None, value=None)
Create a request for accessing the Boss' metadata service.
Do not use this method for list operations. Instead, use the
get_request() method.
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
key (string): Name of key to operate on. Defaults to None.
value (string): Value to assign to key Defaults to None.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_metadata_request(
self, resource, method, content, url_prefix, token,
key=None, value=None):
"""Create a request for accessing the Boss' metadata service.
Do not use this method for list operations. Instead, use the
get_request() method.
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
key (string): Name of key to operate on. Defaults to None.
value (string): Value to assign to key Defaults to None.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
url = self.build_metadata_url(resource, url_prefix, key, value)
headers = self.get_headers(content, token)
return Request(method, url, headers = headers)
def get_permission_request(
self, method, content, url_prefix, token, query_params=None, post_data=None)
Generate a request for manipulating permissions of a data model object.
Manipulate what members of the named group can do with the given data
model object.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
query_params (dict): Query params for GET requests. Defaults to None.
post_data (dict): POST body data. Defaults to None.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_permission_request(self, method, content, url_prefix, token, query_params=None, post_data=None):
"""Generate a request for manipulating permissions of a data model object.
Manipulate what members of the named group can do with the given data
model object.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
query_params (dict): Query params for GET requests. Defaults to None.
post_data (dict): POST body data. Defaults to None.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
if url_prefix is None or url_prefix == '':
raise RuntimeError('url_prefix required.')
url = (url_prefix + '/' + self.version + '/permissions/')
headers = self.get_headers(content, token)
if method == "GET" or method == "DELETE":
return Request(method, url, headers=headers, params=query_params)
else:
# Assuming POST or PATCH
return Request(method, url, headers=headers, json=post_data)
def get_request(
self, resource, method, content, url_prefix, token, proj_list_req=False, json=None, data=None)
Create a request for accessing the Boss' data model services.
Use for the project service or listing keys via the metadata service.
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
proj_list_req (bool): Set to True if performing a list operation on the project service. Defaults to False.
json (dict): POST body data. Defaults to None.
data (): Raw data. Defaults to None.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_request(self, resource, method, content, url_prefix, token, proj_list_req=False, json=None, data=None):
"""Create a request for accessing the Boss' data model services.
Use for the project service or listing keys via the metadata service.
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
proj_list_req (bool): Set to True if performing a list operation on the project service. Defaults to False.
json (dict): POST body data. Defaults to None.
data (): Raw data. Defaults to None.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
if isinstance(resource, CoordinateFrameResource):
service = 'coord'
else:
service = 'collection'
if proj_list_req:
req_type = 'list'
else:
req_type = 'normal'
url = self.build_url(resource, url_prefix, service, req_type)
headers = self.get_headers(content, token)
req = Request(method, url, headers = headers, json = json, data = data)
return req
def get_reserve_request(
self, resource, method, content, url_prefix, token, num_ids)
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
num_ids (int): Number of ids to reserve.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_reserve_request(
self, resource, method, content, url_prefix, token, num_ids):
"""
Args:
resource (intern.resource.boss.BossResource): Resource to perform operation on.
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
num_ids (int): Number of ids to reserve.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
if url_prefix is None or url_prefix == '':
raise RuntimeError('url_prefix required.')
url = (url_prefix + '/' + self.version + '/reserve/' +
resource.get_reserve_route() + '/{}'.format(num_ids))
headers = self.get_headers(content, token)
return Request(method, url, headers=headers)
def get_user_request(
self, method, content, url_prefix, token, user, first_name=None, last_name=None, email=None, password=None)
Generate a request for working with the /sso endpoint.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
user (string): Name of user.
first_name (optional[string]): User's first name. Defaults to None.
last_name (optional[string]): User's last name. Defaults to None.
email: (optional[string]): User's email address. Defaults to None.
password: (optional[string]): User's password. Defaults to None.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_user_request(
self, method, content, url_prefix, token, user, first_name=None,
last_name=None, email=None, password=None):
"""Generate a request for working with the /sso endpoint.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
user (string): Name of user.
first_name (optional[string]): User's first name. Defaults to None.
last_name (optional[string]): User's last name. Defaults to None.
email: (optional[string]): User's email address. Defaults to None.
password: (optional[string]): User's password. Defaults to None.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
if url_prefix is None or url_prefix == '':
raise RuntimeError('url_prefix required.')
data = {}
url = url_prefix + '/' + self.version + '/sso/user/' + user
if first_name is not None:
data['first_name'] = first_name
if last_name is not None:
data['last_name'] = last_name
if email is not None:
data['email'] = email
if password is not None:
data['password'] = password
headers = self.get_headers(content, token)
return Request(method, url, headers=headers, json=data)
def get_user_role_request(
self, method, content, url_prefix, token, user, role=None)
Generate a request for manipulating roles for a user.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
user (string): Name of user.
role (optional[string]): Name of role. Defaults to None.
Returns
(requests.Request): A newly constructed Request object.
Raises
RuntimeError if url_prefix is None or an empty string.
def get_user_role_request(
self, method, content, url_prefix, token, user, role=None):
"""Generate a request for manipulating roles for a user.
Args:
method (string): HTTP verb such as 'GET'.
content (string): HTTP Content-Type such as 'application/json'.
url_prefix (string): protocol + initial portion of URL such as https://api.theboss.io Do not end with a forward slash.
token (string): Django Rest Framework token for auth.
user (string): Name of user.
role (optional[string]): Name of role. Defaults to None.
Returns:
(requests.Request): A newly constructed Request object.
Raises:
RuntimeError if url_prefix is None or an empty string.
"""
if url_prefix is None or url_prefix == '':
raise RuntimeError('url_prefix required.')
url = url_prefix + '/' + self.version + '/sso/user-role/' + user
if role is not None:
url = url + '/' + role
headers = self.get_headers(content, token)
return Request(method, url, headers=headers)
def reserve_ids(
self, resource, num_ids, url_prefix, auth, session, send_opts)
Reserve a block of unique, sequential ids for annotations.
Args:
resource (intern.resource.Resource): Resource should be an annotation channel.
num_ids (int): Number of ids to reserve.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns
(int): First id reserved.
Raises
(TypeError): resource is not a channel or not an annotation channel.
def reserve_ids(
self, resource, num_ids,
url_prefix, auth, session, send_opts):
"""Reserve a block of unique, sequential ids for annotations.
Args:
resource (intern.resource.Resource): Resource should be an annotation channel.
num_ids (int): Number of ids to reserve.
url_prefix (string): Protocol + host such as https://api.theboss.io
auth (string): Token to send in the request header.
session (requests.Session): HTTP session to use for request.
send_opts (dictionary): Additional arguments to pass to session.send().
Returns:
(int): First id reserved.
Raises:
(TypeError): resource is not a channel or not an annotation channel.
"""
if not isinstance(resource, ChannelResource):
raise TypeError('resource must be ChannelResource')
if resource.type != 'annotation':
raise TypeError('Channel is not an annotation channel')
req = self.get_reserve_request(
resource, 'GET', 'application/json', url_prefix, auth, num_ids)
prep = session.prepare_request(req)
resp = session.send(prep, **send_opts)
if resp.status_code == 200:
json_data = resp.json()
return int(json_data['start_id'])
msg = ('Reserve ids failed on {}, got HTTP response: ({}) - {}'.format(
resource.name, resp.status_code, resp.text))
raise HTTPError(msg, request=req, response=resp)


Lorem ipsum dolor sit amet, consectetur adipiscing elit quis risus eget urna mollis consectetur adipiscing elit.
Is it possible to control man’s mental evolution so as to make him proof against the psychosis of hate and destructiveness?
Here I am thinking by no means only of the so-called uncultured masses. Experience proves that it is rather the so-called “intelligentsia” that is most apt to yield to these disastrous collective suggestions, since the intellectual has no direct contact with life in the raw but encounters it in its easiest, synthetic form — upon the printed page. … But … here we have the best occasion of discovering ways and means to render all armed conflicts impossible.
I know that in your writings we may find answers, explicit or implied, to all the issues of this urgent and absorbing problem. But it would be of the greatest service to us all were you to present the problem of world peace in the light of your most recent discoveries, for such a presentation well might blaze the trail for new and fruitful modes of action.


{% comment %} This is the 'my account password' page. Here, a user can change their current password. {% endcomment %}


| conquer {conquer} | R Documentation |
Fit a smoothed quantile regression via convolution-type smoothing method. The solution is computed using gradient descent with Barzilai-Borwein step size. Constructs (1-alpha) confidence intervals with multiplier bootstrap.
conquer( X, Y, tau = 0.5, kernel = c("Gaussian", "uniform", "parabolic", "triangular"), h = 0, checkSing = FALSE, tol = 1e-04, iteMax = 5000, ci = FALSE, alpha = 0.05, B = 1000 )
X |
A n by p design matrix. Each row is a vector of observation with p covariates. Number of observations n must be greater than number of covariates p. |
Y |
An n-dimensional response vector. |
tau |
(optional) The desired quantile level. Default is 0.5. Value must be between 0 and 1. |
kernel |
(optional) A character string specifying the choice of kernel function. Default is "Gaussian". Other choices are "Gaussian", "uniform", "parabolic" or "triangular". |
h |
(optional) The bandwidth parameter for kernel smoothing. Default is max(((log(n) + p) / n)^{0.4}, 0.05). The default will be used if the input value is less than 0.05. |
checkSing |
(optional) A logical flag. Default is FALSE. If |
tol |
(optional) Tolerance level of the gradient descent algorithm. The gradient descent algorithm terminates when the maximal entry of the gradient is less than |
iteMax |
(optional) Maximum number of iterations. Default is 5000. |
ci |
(optional) A logical flag. Default is FALSE. If |
alpha |
(optional) The nominal level for (1-alpha)-confidence intervals. Default is 0.05. The input value must be in (0, 1). |
B |
(optional) The size of bootstrap samples. Default is 1000. |
An object containing the following items will be returned:
coeff
A (p + 1)-vector of estimated quantile regression coefficients, including the intercept.
ite
The number of iterations of the gradient descent algorithm for convergence.
residual
The residuals of the quantile regression fit.
bandwidth
The value of smoothing bandwidth.
tau
The desired quantile level.
kernel
The choice of kernel function.
n
The sample size.
p
The dimension of the covariates.
perCI
The percentile confidence intervals for regression coefficients. Not available if ci = FALSE
.
pivCI
The pivotal confidence intervals for regression coefficients. Not available if ci = FALSE
normCI
The normal-based confidence intervals for regression coefficients. Not available if ci = FALSE
Xuming He<EMAIL_ADDRESS>Xiaoou Pan<EMAIL_ADDRESS>Kean Ming Tan<EMAIL_ADDRESS>and Wen-Xin Zhou<EMAIL_ADDRESS>Barzilai, J. and Borwein, J. M. (1988). Two-point step size gradient methods. IMA J. Numer. Anal. 8 141–148.
Fernandes, M., Guerre, E. and Horta, E. (2019). Smoothing quantile regressions. J. Bus. Econ. Statist., in press.
He, X., Pan, X., Tan, K. M., and Zhou, W.-X. (2020). Smoothed quantile regression for large-scale inference. Preprint.
Koenker, R. and Bassett, G. (1978). Regression quantiles. Econometrica 46 33-50.
n = 500; p = 10 beta = rep(1, p) X = matrix(rnorm(n * p), n, p) Y = 1 + X %*% beta + rt(n, 2) ## Smoothed quantile regression with Gaussian kernel fit.Gauss = conquer(X, Y, tau = 0.5, kernel = "Gaussian") beta.hat.Gauss = fit.Gauss$coeff ## Smoothe quantile regression with uniform kernel fit.unif = conquer(X, Y, tau = 0.5, kernel = "uniform") beta.hat.unif = fit.unif$coeff ## Construct three types of confidence intervals via multiplier bootstrap fit = conquer(X, Y, tau = 0.5, kernel = "Gaussian", ci = TRUE) ci.per = fit$perCI ci.piv = fit$pivCI ci.norm = fit$normCI


An analysis of tweets from the Rethinking Cancer - UCL Cancer Domain - May 2019 conference. A total of 292 tweets from 80 users were collected using the rtweet
R package.
Data were last collected on 2019-05-14 10:09:19
Filtered for dates 2019-05-13 - 2019-05-13 in the Europe/London timezone.
The “replies network”, composed from users who reply directly to one another, coloured by page rank.
The “mentions network”, where users mention other users in their tweets. Node colour, label size and alpha adjusted according to PageRank score.
| screen_name | text | retweet_count |
|---|---|---|
| UCLCancerECN |
Welcome to the Early Career #UCLCancerDomain! Our brilliant co-chairs @marina_parry and @mariasecrier introduce our brand new shiny network. Follow us for early career networking events, training, and all things #CancerResearch. @ucl_slms @uclcancer https://t.co/EhGQSJEidA |
10 |
| UCLCancerECN |
Say hello to our fantastic ECN #UCLCancerDomain committee members! We’re here to organise you top #CancerResearch events and networking opps. Follow us:@marina_parry @mariasecrier @EmilyPMcBride @PinkieChambers @mmkoo12 @LRodriguezArco @pilar_acedo @patrickhales @ClaireVGarnett https://t.co/c8x0yYy4X2 |
7 |
| UCLCancerECN | Big shout out to all #earlycareer researchers (Masters, PhDs, postdocs and beyond) attending today’s #UCLCancerDomain Symposium! Pop by our #earlycareer network stall and help us map #CancerResearch across UCL. @ucl_slms | 7 |
| UCLCancerECN | Only a week to go until the #UCLCancerDomain Symposium where our shortlisted #earlycareer researchers will be showcasing the latest cancer research across UCL! #postdoclife #PhDlife #CancerResearch | 7 |
| ucl_slms | Only 3 days until the #UCLCancerDomain Symposium | Rethinking Cancer! It will be fascinating day of talks, networking and discussion sessions. Some of our speakers are: @MarcelLevi @MazzucatoM @andrew_pom @CharlesSwanton @ebeecham1 @mmkoo12 @cd_steele @mrsprostate @Norapashayan | 6 |
| IIPP_UCL | IIPP Director @MazzucatoM gives a keynote lecture at the @uclcancer Domain Symposium #UCLCancerDomain on Rethinking Cancer, drawing from our report launched last year on re-imagining health innovation to deliver public value. Learn more about the report: https://t.co/mDaOooflKW https://t.co/62bTr35CVB | 5 |
| lungsforliving | Charlie Swanton guides us through the early evolutionary mechanisms of lung cancer defined by his extraordinary TracerX trial and team and demonstrates the potential ‘Achilles heal’ of lung cancer through aggressive targeting of neo-Ags #uclcancerdomain https://t.co/RJeDCgDbKu | 5 |
| Jo_WallerUCL | Acknowledging Jane Wardle and Sammy Quaife’s important contribution to uptake of lung screening @UCL_BSH @QuaifeS @lungsforliving #UCLCancerDomain https://t.co/Di2Xyn2FBc | 5 |
| jsvaidya | Prof Daniel Hochhauser starting off the first UCL cancer domain symposium-Rethinking Cancer #UCLCancerDomain @ucl_slms @uclcancer https://t.co/yTkb1CAwtS | 5 |
| jsvaidya | Prof Charles Swanton explain how 100 patients with ‘lung cancer’ actually have 100 different types of cancers #UCLCancerDomain @ucl_slms @uclcancer https://t.co/vWx5Uu86ON | 5 |
| screen_name | text | favorite_count |
|---|---|---|
| mmkoo12 | A little nervous about speaking between leading cancer researchers at UCL tomorrow but pleased to be flying the #epidemiology and #publichealth flag in front of such a broad audience! #UCLCancerDomain #postdoclife https://t.co/1tyW8C6QVO | 39 |
| Jo_WallerUCL | Acknowledging Jane Wardle and Sammy Quaife’s important contribution to uptake of lung screening @UCL_BSH @QuaifeS @lungsforliving #UCLCancerDomain https://t.co/Di2Xyn2FBc | 28 |
| lungsforliving | Charlie Swanton guides us through the early evolutionary mechanisms of lung cancer defined by his extraordinary TracerX trial and team and demonstrates the potential ‘Achilles heal’ of lung cancer through aggressive targeting of neo-Ags #uclcancerdomain https://t.co/RJeDCgDbKu | 21 |
| EmilyPMcBride |
Dr @mmkoo12 smashing her early diagnosis in #CancerResearch talk at #UCLCancerDomain and flying the flag for #PopulationHealth. @ucl_slms @UCL_BSH https://t.co/nQb2uShHop |
19 |
| Ayyliinn | Prof. Gary Royle from @UCLmedphys and @ProtonAdvanceRT presenting on targeting tumours with protons. #UCLCancerDomain #UCL @UCL https://t.co/F6OCbLTHgI | 16 |
| UCL_BSH | Prof Sam Janes talking about the importance of behavioural science in stratified #lungcancer screening - important research led by @QuaifeS @mamta_ruparel #BSHresearch #UCLCancerDomain https://t.co/h9imTTTTlA | 15 |
| PereiraGroup | UCL Cancer Domain Symposium kicking off! 🧬🧫 Loads of great talks ahead! #UCLCancerDomain @ucl_slms @UCLCancerECN https://t.co/Ju3wVF6Bvd | 14 |
| jsvaidya | Prof Charles Swanton explain how 100 patients with ‘lung cancer’ actually have 100 different types of cancers #UCLCancerDomain @ucl_slms @uclcancer https://t.co/vWx5Uu86ON | 14 |
| Jo_WallerUCL | Risk of #overdiagnosis in prostate cancer screening @mrsprostate #UCLCancerDomain https://t.co/EFBosQtpTv | 13 |
| UCLTRO | @IIPP_UC Director Prof. @MazzucatoM gave an engaing keynote lecture at today’s #UCLCancerDomain symposium. We need co-creation with the pharma industry and to make strategic decisions to encourage good practice. #UCLCancerDomain @ucl_slms @UCLTRO https://t.co/QZYnodESIk | 12 |
| screen_name | text | quote_count |
|---|---|---|
| mrsprostate | Looking forward to the #UCLCancerDomain symposium tomorrow! @ucl_slms @UCLDivofSurgery https://t.co/Eks2xpAZVJ | 2 |
| mmkoo12 | A little nervous about speaking between leading cancer researchers at UCL tomorrow but pleased to be flying the #epidemiology and #publichealth flag in front of such a broad audience! #UCLCancerDomain #postdoclife https://t.co/1tyW8C6QVO | 2 |
| screen_name | text | favorite_count |
|---|---|---|
| Jo_WallerUCL | Acknowledging Jane Wardle and Sammy Quaife’s important contribution to uptake of lung screening @UCL_BSH @QuaifeS @lungsforliving #UCLCancerDomain https://t.co/Di2Xyn2FBc | 28 |
| lungsforliving | Charlie Swanton guides us through the early evolutionary mechanisms of lung cancer defined by his extraordinary TracerX trial and team and demonstrates the potential ‘Achilles heal’ of lung cancer through aggressive targeting of neo-Ags #uclcancerdomain https://t.co/RJeDCgDbKu | 21 |
| EmilyPMcBride |
Dr @mmkoo12 smashing her early diagnosis in #CancerResearch talk at #UCLCancerDomain and flying the flag for #PopulationHealth. @ucl_slms @UCL_BSH https://t.co/nQb2uShHop |
19 |
| Ayyliinn | Prof. Gary Royle from @UCLmedphys and @ProtonAdvanceRT presenting on targeting tumours with protons. #UCLCancerDomain #UCL @UCL https://t.co/F6OCbLTHgI | 16 |
| UCL_BSH | Prof Sam Janes talking about the importance of behavioural science in stratified #lungcancer screening - important research led by @QuaifeS @mamta_ruparel #BSHresearch #UCLCancerDomain https://t.co/h9imTTTTlA | 15 |
| PereiraGroup | UCL Cancer Domain Symposium kicking off! 🧬🧫 Loads of great talks ahead! #UCLCancerDomain @ucl_slms @UCLCancerECN https://t.co/Ju3wVF6Bvd | 14 |
| jsvaidya | Prof Charles Swanton explain how 100 patients with ‘lung cancer’ actually have 100 different types of cancers #UCLCancerDomain @ucl_slms @uclcancer https://t.co/vWx5Uu86ON | 14 |
| Jo_WallerUCL | Risk of #overdiagnosis in prostate cancer screening @mrsprostate #UCLCancerDomain https://t.co/EFBosQtpTv | 13 |
| UCLTRO | @IIPP_UC Director Prof. @MazzucatoM gave an engaing keynote lecture at today’s #UCLCancerDomain symposium. We need co-creation with the pharma industry and to make strategic decisions to encourage good practice. #UCLCancerDomain @ucl_slms @UCLTRO https://t.co/QZYnodESIk | 12 |
| UCLTRO | Today we are at the 1st #UCLCancerDomain Symposium. Exciting programme demonstrating the breadth of @ucl #researchexcellence in cancer biology, it’s #diagnosis and treatment. @ucl_slms @UCLTRO https://t.co/R0lfQJN3bh | 12 |
The top 100 words used 3 or more times.
Words that were tweeted next to each other at least 5 times.
Top 10 words associated with 6 topics identified by LDA.
Most representative tweets for each topic
| screen_name | text | gamma |
|---|---|---|
| IIPP_UCL | Can a Health Advanced Research Projects Agency (HARPA) modelled on Defense Advanced Research Projects Agency (DARPA) speed up the translation of key scientific discoveries into much-needed medicines and diagnostic tools, and their commercialisation? @MazzucatoM #UCLCancerDomain https://t.co/S5kuBe4JoF | 0.9949833 |
| UCLCancerECN |
Heart disease and cancer are the biggest killers in the UK, but the common driver behind all is ageing. So the broader question becomes: what causes ageing? Prof David Gems discusses the leading theories. #UCLCancerDomain https://t.co/hFCo1Qb1ZH |
0.9939348 |
| JavierHerrero7 | @ucl_slms Just realising that the first question relates to gender balance in speakers so far. While start has been male only, I am glad to see that the overall balance is 8F/9M speakers and 5F/4M chairs throughout the whole symposium #UCLCancerDomain @ucl_slms | 0.9932270 |
| UCLCancerECN | Early detections vs early diagnosis, detection consensus, overdiagnosis, cancer heterogeneity and detection… Exciting discussion and food for thought in the panel discussion of session 3, at the #UCLCancerDomain symposium. https://t.co/0kLMAXt0tI | 0.9928074 |
| JavierHerrero7 | .@mmkoo12 - Understanding incidence of symptoms like abdominal pain, breast lump, fatigue, etc. =? implications for prevention for instance. See more info on ECHO group webpage: https://t.co/t94dFneVIX #UCLCancerDomain @ucl_slms #UCLCancerDomainECN | 0.9928074 |
| Jo_WallerUCL | Common theme of risk communication at #SFgenomes19 this morning and #UCLCancerDomain this afternoon. Lots of scope for health psychologists to help optimise delivery of test/screening results @UCL_BSH | 0.9928074 |
| mmkoo12 | Nice to see @CRUKresearch infographics being used in Prof Caroline Moore’s talk on the tension between early detection and #overdiagnosis for prostate cancer #PSAtest #ProstateCancer #UCLCancerDomain https://t.co/tMoCsC9RlX | 0.9923323 |
| CosmicArturo | Great to hear CAR-T cell therapy is now established in the UK as part of the NHS arsenal against cancer. So much progress reported by Claire Roddie at #UCLCancerDomain https://t.co/5J9xx30qwu | 0.9917900 |
| ucl_slms | Great to hear the interesting and thought provoking panel discussion of session one with all the speakers and moderators on the subject of: Cancer evolution: can we beat Nature? #UCLCancerDomain Symposium | 0.9911651 |
| ucl_slms | Don’t forget to come and visit our sponsor stands at the #UCLCancerDomain Symposium, located in the Jeffery @2BScientific @BioLegend @CambridgeBiosci @CellSignal @LICORBio @PerkinElmer @StillaTech | 0.9911651 |
| screen_name | text | gamma |
|---|---|---|
| JavierHerrero7 | Duncan Greig — Basis of resistance: in bacteria + antibiotics, colony develops resistance. However, individual cells are not: can be retreated. In yeast (Levy et al, PLOS Biol 2012) similar results: slow growing cells are more resistant to env stress. #UCLCancerDomain @ucl_slms | 0.9953824 |
| UCLCancerECN | Low dose computed tomographic screening reduces lung cancer in 20% and it is cost effective! Prof. Janes (@lungsforliving) shows the invitation material designed by his team for the NHS aimed at extending the use of this technique at GP practices. #UCLCancerDomain | 0.9947567 |
| JavierHerrero7 | .@CharlesSwanton Diversity (ITH) vs outcome? Indeed, splitting high CIN vs low CIN in fist 100 lung #TRACERx show high ITH with poor outcome. For instance, recurrent mutations in the same drivers in different clones/regions of the same tumour #UCLCancerDomain @ucl_slms @uclcancer | 0.9945086 |
| JavierHerrero7 | Duncan Greig — Basis of resistance: Positioning different processes in a 2D graph of reversible vs non-reservable and specific vs random mutations, shows differences between evolvability and phenotypic plasticity, although are related #UCLCancerDomain @ucl_slms | 0.9936004 |
| Orla_McCourt | Fascinating presentation from @ebeecham1 on her work on understanding meaning of quality of life in children with high risk brain tumors from discussions between clinicians, parents & children. Look forward to following this work! @UCLCancerECN #UCLCancerDomain | 0.9928074 |
| UCLCancerECN | Lung cancer is the most common cause of cancer death in the UK, Professor Sam Janes (@lungsforliving) explains. Techniques such as autofluorescence bronchoscopy are key to detect it. #UCLCancerDomain https://t.co/czqJ2oMNrl | 0.9928074 |
| rociorojib | Dr. Duncan Greig talking about microbes as models for cancer resistance to drugs. Mutations are random, natural selection determinants and yeast as an example #UCLCancerDomain @ucl_slms https://t.co/bI4pGBlXIM | 0.9928074 |
| UCLCancerECN |
Up next: Evolutionary biologist Dr Duncan Greig discussing microbes as models for cancer evolution. #UCLCancerDomain #CancerResearch #cancer https://t.co/9xgvF2EaIN |
0.9911651 |
| IIPP_UCL | By focusing on profit over patients, the prevailing discourse around drug pricing is throwing the baby out with the bathwater, and those who need treatment the most are the ones who suffer. @MazzucatoM #UCLCancerDomain https://t.co/mrq9Ts0IPj | 0.9911651 |
| JavierHerrero7 | .@CharlesSwanton talking about cancer evolution and why this is important. Initial studies led to TRACERx in lung (https://t.co/FMlCd9UsSs) and kidney (https://t.co/3INoNxLfqS) #UCLCancerDomain @ucl_slms @uclcancer | 0.9904374 |
| DanMarcu | @CharlesSwanton starting the #UCLCancerDomain with the evolutionary mechanisms and diversity in tumour #cancer #genetics #evolution #science #cure @UCLCancerECN @uclcancer https://t.co/XryCnw4gc8 | 0.9904374 |
| screen_name | text | gamma |
|---|---|---|
| JavierHerrero7 | Tariq Enver — ETV6-RUNX1 prevents differentiation, maintains myeloid programme in lymphoid-meant cell, also induces quiescent and enables overactive RAG giving rise to additional mutations. #UCLCancerDomain @ucl_slms @uclcancer | 0.9945086 |
| JavierHerrero7 | Christopher Steele (@cd_steele): Molecular fingerprints of copy number alterations in human cancer. Automated detection of CN signatures in sarcoma. See full article: https://t.co/A1CPqwxkZm #UCLCancerDomain @ucl_slms #UCLCancerDomainECN @uclcancer | 0.9932270 |
| JavierHerrero7 | Tariq Enver — mentions Böiers, Richardson et al (https://t.co/pIb77m255r) showing the effect of ETV6-RUNX1 on the transcriptional programme, blocking the differentiation programme #UCLCancerDomain @ucl_slms @uclcancer https://t.co/8NT8Ll4ipE | 0.9928074 |
| JavierHerrero7 | Yin Wu — Immune checkpoint inhibitors not always work? Need stimulatory signals. Look at role of Gamma-delta T cells (gdT). Are they resident? Do they correlate with outcome? #UCLCancerDomain @ucl_slms #UCLCancerDomainECN @uclcancer | 0.9928074 |
| JavierHerrero7 | Yin Wu — Analysis of TCR clonotypes within tumours. — This is one of the topics we work on as part of the @CR_UK funded Cancer ImmunoTherapy Accelerator (CITA) network. #UCLCancerDomain @ucl_slms #UCLCancerDomainECN @uclcancer | 0.9923323 |
| UCLCancerECN |
Our next brilliant early career researcher Christopher Steele speaking about his #CancerResearch: Molecular fingerprints of copy number alterations in human cancer. Fascinating! #UCLCancerDomain @ucl_slms https://t.co/MrF17DRhMI |
0.9923323 |
| UCLCancerECN |
Welcome to the Early Career #UCLCancerDomain! Our brilliant co-chairs @marina_parry and @mariasecrier introduce our brand new shiny network. Follow us for early career networking events, training, and all things #CancerResearch. @ucl_slms @uclcancer https://t.co/EhGQSJEidA |
0.9917900 |
| CosmicArturo | Signature method for copy number studies by Christopher Steele. Can we finally know the effects of aneuploidy in cancer? Research close to my heart. #UCLCancerDomain https://t.co/mwpeOIBqEL | 0.9917900 |
| UCLCancerECN | Prof @CharlesSwanton delivering brilliant talk on cancer evolution, immune evasion and metastatic progression. #UCLCancerDomain #CancerResearch https://t.co/X8L0xLzXEu | 0.9911651 |
| UCLCancerECN |
Say hello to our fantastic ECN #UCLCancerDomain committee members! We’re here to organise you top #CancerResearch events and networking opps. Follow us:@marina_parry @mariasecrier @EmilyPMcBride @PinkieChambers @mmkoo12 @LRodriguezArco @pilar_acedo @patrickhales @ClaireVGarnett https://t.co/c8x0yYy4X2 |
0.9911651 |
| screen_name | text | gamma |
|---|---|---|
| lungsforliving | Charlie Swanton guides us through the early evolutionary mechanisms of lung cancer defined by his extraordinary TracerX trial and team and demonstrates the potential ‘Achilles heal’ of lung cancer through aggressive targeting of neo-Ags #uclcancerdomain https://t.co/RJeDCgDbKu | 0.9949833 |
| UCLCancerECN |
Lydia Neary-Zajiczek is our next early career researcher speaking about image registration, segmentation, and region growing to generate sampel stiffness maps of cancerous and healthy tissue. Brilliant work Lydia! #UCLCancerDomain @ucl_slms https://t.co/yDk9SHQFnC |
0.9945086 |
| JavierHerrero7 | C. Moore — Reviews PC tests. Early ones include how much urine was left in the bladder, duration of symptoms, bone pain. Then finger, needle. Ultrasound in the mobile unit performed on a chair with an (un)inviting opening for the test #UCLCancerDomain @ucl_slms | 0.9945086 |
| IIPP_UCL | IIPP Director @MazzucatoM gives a keynote lecture at the @uclcancer Domain Symposium #UCLCancerDomain on Rethinking Cancer, drawing from our report launched last year on re-imagining health innovation to deliver public value. Learn more about the report: https://t.co/mDaOooflKW https://t.co/62bTr35CVB | 0.9942360 |
| JavierHerrero7 | .@CharlesSwanton referring to the loss of HLA as mechanism of Immune escape (see LOHHLA paper: https://t.co/q01wr8uzCv). Very commonly happening sub-clonally and more prominent in highly immune infiltrated tumours #UCLCancerDomain @ucl_slms @uclcancer | 0.9936004 |
| mariasecrier | Our brilliant ECN committee member Monica Koo @mmkoo12 won the runner up prize at the Rethinking Cancer symposium @UCL. Congratulations, fantastic talk! #UCLCancerDomain #UCLCancerDomainECN https://t.co/fcKav0jzY4 | 0.9932270 |
| ucl_slms | Only 3 days until the #UCLCancerDomain Symposium | Rethinking Cancer! It will be fascinating day of talks, networking and discussion sessions. Some of our speakers are: @MarcelLevi @MazzucatoM @andrew_pom @CharlesSwanton @ebeecham1 @mmkoo12 @cd_steele @mrsprostate @Norapashayan | 0.9928074 |
| IIPP_UCL | Why do we need a missions approach when it comes to cancer? Because cancer is a highly multidisciplinary issue and certain approaches won’t work if efforts are pulled in different directions, says IIPP Director @MazzucatoM #UCLCancerDomain https://t.co/bSWy4maVfy | 0.9923323 |
| CosmicArturo | UCLH is incorporating proton therapy for cancer, explained by Gary Royle. Some controversies for this therapy arise in prostate cancer in the US #UCLCancerDomain https://t.co/VzCOOYb7iV | 0.9917900 |
| JavierHerrero7 | Starting the “Rethinking Cancer” Symposium organised by the UCL Cancer Domain. For questions, discussions, etc: https://t.co/5xLnE5ztEt event num. 6906 #UCLCancerDomain @ucl_slms @uclcancer | 0.9911651 |
| screen_name | text | gamma |
|---|---|---|
| IIPP_UCL | UK government and charity funding esp vital to cancer research (@NCRI_partners spends more than £490m each year). Making sure that innovative treatments are affordable is not simply about redistribution, but about public return on public investment: @MazzucatoM #UCLCancerDomain https://t.co/jWJredWlNG | 0.9945086 |
| UCLCancerECN | @Norapashayan compares risk-stratified screenening as opposed to the current age-based screening offered by NHS to conclude that risk-stratified could improve benefit-harm trade-offs #UCLCancerDomain https://t.co/OJA8KBuDUN | 0.9942360 |
| IIPP_UCL | Countries have increasingly recognised the importance of framing cancer research as missions which requires the same level of ambition, aspiration and resources as the moonshot (putting man on the Moon), says IIPP Director @MazzucatoM #UCLCancerDomain https://t.co/sdklRgokft | 0.9939348 |
| mmkoo12 | A little nervous about speaking between leading cancer researchers at UCL tomorrow but pleased to be flying the #epidemiology and #publichealth flag in front of such a broad audience! #UCLCancerDomain #postdoclife https://t.co/1tyW8C6QVO | 0.9932270 |
| GLyratzopoulos | Congrats to @mmkoo12 runner up for best early career researcher oral presentation at #UCLCancerDomain Day 2019. Together with @Norapashayan representing population health sciences amidst a constellation of outstanding biological and clinical researchers | 0.9932270 |
| UCLCancerECN | Big shout out to all #earlycareer researchers (Masters, PhDs, postdocs and beyond) attending today’s #UCLCancerDomain Symposium! Pop by our #earlycareer network stall and help us map #CancerResearch across UCL. @ucl_slms | 0.9928074 |
| UCLTRO | @IIPP_UC Director Prof. @MazzucatoM gave an engaing keynote lecture at today’s #UCLCancerDomain symposium. We need co-creation with the pharma industry and to make strategic decisions to encourage good practice. #UCLCancerDomain @ucl_slms @UCLTRO https://t.co/QZYnodESIk | 0.9928074 |
| ucl_slms | Session 2 at the #UCLCancerDomain Symposium is showcasing the best of the Early Career speaker presentations from the broad UCL cancer community @UCLCancerECN@ebeecham1 @mmkoo12 @cd_steele https://t.co/YvJsiDfd8Y | 0.9911651 |
| uclmedsci | This time next week, we’ll be kicking off the inaugural #UCLCancerDomain Symposium | Rethinking Cancer. Register today for this free event https://t.co/eCnMY0SMem https://t.co/uYADgUDAmo | 0.9904374 |
| UCLCancerECN | Only a week to go until the #UCLCancerDomain Symposium where our shortlisted #earlycareer researchers will be showcasing the latest cancer research across UCL! #postdoclife #PhDlife #CancerResearch | 0.9904374 |
| UCLCancerECN | Good morning UCL! Almost all of our #CancerECN committee members are attending the #UCLCancerDomain symposium today - a fantastic line up of speakers and talks to look forward to. #CancerResearch | 0.9904374 |
| marina_parry | A really fab team to work with! If you’re at the #UCLCancerDomain Symposium, drop by our stand or get in touch on Twitter or by email and let us know how we can help you get the most out of your time @ucl. #ECRchat https://t.co/Ynb1iWdNRs | 0.9904374 |
| screen_name | text | gamma |
|---|---|---|
| IIPP_UCL | It’s thought that we have a limited pot of money and assume social goals conflict with each other. Not so: choose missions smartly, structure the funding effectively, design policies effectively. There’s no reason why different missions can’t co-exist @MazzucatoM #UCLCancerDomain https://t.co/oOZBA3v3Pe | 0.9942360 |
| JavierHerrero7 | Alexandra Lubin talking about automated Zebrafish identification whole organism screening. Hearing about zebrafish reminds me of my earlier days at the @emblebi in the @ensembl team: https://t.co/saXixnaxln #UCLCancerDomain @ucl_slms #UCLCancerDomainECN @uclcancer | 0.9936004 |
| JavierHerrero7 | C. Moore — Modelling study: how many positive tests vs how much over-treated. PSA detection (especially if as early as posible) lead to too many false positive and still miss cases. MRI + targeted biopsy shown to work best. #UCLCancerDomain @ucl_slms | 0.9932270 |
| UCL_BSH | Prof Sam Janes talking about the importance of behavioural science in stratified #lungcancer screening - important research led by @QuaifeS @mamta_ruparel #BSHresearch #UCLCancerDomain https://t.co/h9imTTTTlA | 0.9928074 |
| CosmicArturo | @MazzucatoM at #UCLCancerDomain advocates for a global HARPA for mission-oriented healthcare innovation, definancializing drug discovery. She proposes @UCLCancerECN is primed to make this idea a reality! https://t.co/ntKqOXzlmB | 0.9923323 |
| rociorojib | Ageing paradigms. Oxidative damage theory vs/plus antagonistic pleiotropy. David Gems at #UCLCancerDomain. A particular nematode and cancer and ageing. Other senescent pathologies | 0.9917900 |
| Jo_WallerUCL | How to explain to patients that early detection isn’t always good? @Norapashayan calls for more education. Sam Janes talks to patients about dying ‘with not of’ a cancer. @mrsprostate advocates saying ‘not eligible for treatment’ #UCLCancerDomain | 0.9917900 |
| UCLCancerECN |
Alexandra Lubin speaking about her #cancerresearch on automated high-throughput drug screening in zebrafish 🐠 Fasicanting and innovative talk at #UCLCancerDomain ! @ucl_slms https://t.co/1tjYig6Yqi |
0.9911651 |
| UCL_BSH | Lots of BSH researchers in attendance at today’s first #UCLCancerDomain symposium - including a quick-fire talk by @mmkoo12 in the #earlycareers slot. | 0.9904374 |
| mmkoo12 | Prof @MazzucatoM: we have a moonshot approach but no moonshot framework in healthcare. Mission-oriented approach could contribute to health outcomes #UCLCancerDomain | 0.9904374 |
## R version 3.5.1 (2018-07-02)
## Platform: x86_64-apple-darwin15.6.0 (64-bit)
## Running under: macOS 10.14.4
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib
##
## locale:
## [1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] bindrcpp_0.2.2 here_0.1 knitr_1.20
## [4] viridis_0.5.1 viridisLite_0.3.0 ggraph_1.0.2
## [7] wordcloud_2.6 RColorBrewer_1.1-2 ggrepel_0.8.0
## [10] ggplot2_3.0.0 igraph_1.2.2 topicmodels_0.2-8
## [13] tidytext_0.2.0 forcats_0.3.0 lubridate_1.7.4
## [16] tidyr_0.8.1 dplyr_0.7.6 rtweet_0.6.8
##
## loaded via a namespace (and not attached):
## [1] Rcpp_0.12.19 lattice_0.20-35 utf8_1.1.4
## [4] assertthat_0.2.0 rprojroot_1.3-2 digest_0.6.18
## [7] ggforce_0.1.3 slam_0.1-45 R6_2.3.0
## [10] plyr_1.8.4 backports_1.1.2 stats4_3.5.1
## [13] evaluate_0.12 highr_0.7 httr_1.3.1
## [16] pillar_1.3.0 rlang_0.2.2 lazyeval_0.2.1
## [19] Matrix_1.2-14 rmarkdown_1.10 labeling_0.3
## [22] stringr_1.3.1 munsell_0.5.0 broom_0.5.0
## [25] compiler_3.5.1 janeaustenr_0.1.5 pkgconfig_2.0.2
## [28] htmltools_0.3.6 tidyselect_0.2.5 tibble_1.4.2
## [31] gridExtra_2.3 fansi_0.4.0 crayon_1.3.4
## [34] withr_2.1.2 MASS_7.3-50 SnowballC_0.5.1
## [37] grid_3.5.1 nlme_3.1-137 jsonlite_1.5
## [40] gtable_0.2.0 magrittr_1.5 units_0.6-1
## [43] scales_1.0.0 tokenizers_0.2.1 cli_1.0.1
## [46] stringi_1.2.4 farver_1.0 reshape2_1.4.3
## [49] NLP_0.2-0 xml2_1.2.0 tools_3.5.1
## [52] glue_1.3.0 tweenr_1.0.0 purrr_0.2.5
## [55] parallel_3.5.1 yaml_2.2.0 tm_0.7-6
## [58] colorspace_1.3-2 bindr_0.1.1 modeltools_0.2-22


Fill out this form in a few steps to know the time of implementation of Netsuite in your business
Country:
Industry:


Submit your talk
Submit your talk
Check my talk status
We’d like to extend the invitation to you to speak at #tccc{{vm.event.number}}. The same rules from the previous Twin Cities Code Camp events apply:
- We’ll take as many ideas as we get until midnight, {{vm.friendlyLastSubmissionDate}}. After that, we’ll select the sessions and let everyone know if their ideas were accepted or not the following weekend. We'll have 7 rooms available so that means we need 35 sessions. We realize with those who would have to travel that this may be too short of notice, so we’ll try to give those out-of-towners enough notice if their session is in.
- Feel free to send us multiple sessions, but please keep in mind we usually have only one session per speaker.
- The length of a session is 60 minutes.
If you have any questions, reach out to us
on Twitter or
email. Also, please spread the word to other individuals that you think may be interested in speaking at this event.


| Chinese input | |||||
|
Alternate x2
|
Alternate x3
|
Alternate x4
|
Alternate x5
|
Alternate x6
|
|
Split x2
|
Split x3
|
Split x4
|
Split x5
|
Split x6
|
| Text output |