text:
\section{Introduction}
\label{intro}
In 1965, Gordon Moore predicted that the number of transistors in integrated circuits would double every two years \citep{moore_cramming_1965}. This prediction has proved true until now, although semiconductor experts\footnote{From the 2011 executive summary of International Technology Roadmap for Semiconductor (http://www.itrs.net/links/2011itrs/2011Chapters/2011ExecSum.pdf)} expect it to slow down by the end of 2013 (doubling every 3 years instead of 2). The initial emphasis was on producing single core processors with higher processing power. But with increasing heat dissipation problems and higher power consumption, the focus in the last decade has shifted to multicore processors - where each core acts as a separate processor. Each core may have lower processing power compared to a high end single core processor, but it provides better performance by allowing multiple threads to run simultaneously, known as thread-level parallelism (TLP). At present, dual and quad core processors are common place in desktop and laptop machines and even in the current generation of high end smart phones. With both Intel \citep{garver_new_2009} and AMD\footnote{Advanced Micro Devices} working on next generation multicore processors, the potential for utilizing processing power in desktop machines is massive. However, traditional software for scientific applications (e.g. image processing) is written for single-core Central Processing Units (CPU) and is not harnessing the full computational potential of the multicore machines.

Traditionally, high performance computing (HPC) is done on supercomputers with a multitude of processors (and large memory). Computer clusters using commercial off the shelf (COTS) hardware and open source software are also being utilized \citep{szalay_extreme_2011}. And recently graphical processing unit (GPU) based clusters have been put to use for general purpose computing \citep{strzodka_scientific_2005,belleman_high_2008}. The advent of multicore processors provides a unique opportunity to move parallel computing to desktops and laptops, at least for simple tasks. In addition to hardware, one also needs unique software protocols and tools for parallel processing. The two most popular parallel processing protocols are Message Passing Interface (MPI) and OpenMP. MPI is used on machines with distributed memory (for example - clusters) whereas OpenMP is geared towards shared memory systems.

Parallel computing has been used in different sub-fields of astrophysical research. Physical modeling and computationally intensive simulation code have been ported to supercomputers. Examples include N-Body simulation of massive star and galaxy clusters \citep{makino_grape-4:_1997}, radiative transfer \citep{robitaille_hyperion:_2011}, plasma simulation around pulsars, galaxy formation and mergers, cosmology etc. But most of the astronomical image processing and general time consuming data processing and analysis tasks are still run in serial mode. One of the reasons for this is the intrinsic and perceived complexity connected with writing and executing parallel code. Another reason may be that day to day astronomical data processing tasks do not take an extremely long time to execute. Irrespective of this, one can find a few parallel modules developed for astronomical image processing. The cosmic ray removal module CRBLASTER \citep{mighell_crblaster:_2010} is written in C and based on the MPI protocol, and can be executed on supercomputers or cluster computers (as well as on single multicore machines). For co-addition of images, \citet{wiley_astronomy_2011} proposed software based on the MapReduce\footnote{Model to process large data sets on a distributed cluster of computers} algorithm, which is geared towards processing terabytes of data (for example - data generated by big sky surveys like the SDSS\footnote{SDSS: Sloan Digital Sky Survey [http://www.sdss.org/]}) using massively parallel systems.

In this paper, we have explored the other end of the spectrum - single multicore machines. We are proposing a few recipes for utilizing multicore machines for parallel computation, to perform faster execution of astronomical tasks. Our work is targeted at astronomers who are using Python as their preferred scripting language and may be using PyRAF\footnote{PyRAF is a product of the Space Telescope Science Institute, which is operated by AURA for NASA.} or IRAF\footnote{IRAF is distributed by the National Optical Astronomy Observatories, which are operated by the Association of Universities for Research in Astronomy, Inc., under cooperative agreement with the National Science Foundation.} for image/data processing and analysis. The idea is to make the transition from serial to parallel processing as simple as possible for astronomers who do not have experience in high performance computing. Simple IRAF tasks can be rewritten in Python to use parallel processing, but rewriting the more lengthy tasks may not be straightforward. Therefore, instead of rewriting the existing optimized serial tasks, we can use the Python multiprocessing modules to parallelize iterative processes.

In Section \ref{pdp}, we introduce the concept of parallel data processing and the various options available. Python multiprocessing in discussed in Section \ref{python_multiprocessing} with emphasis on native parallel processing implementation. Three different astronomical data processing examples are benchmarked in Section \ref{examples}. In Section \ref{discuss}, we discuss load balancing, scalability, and portability of the parallel Python code. Final conclusions are drawn in Section \ref{conclude}.

\section{Parallel Data Processing}
\label{pdp}
Processors execute instructions sequentially and therefore, from the initial days of computers to the present, most of the applications have been written as serial code. Generally coding and debugging of serial code is much simpler than parallel code. However, debugging is an issue only for parallel programs where many processes depend on results from other processes -  whereas it is not an issue while processing large datasets in parallel. Moving to parallel coding not only requires new hardware and software tools, but also a new way of tackling the problem in hand. To run a program in parallel, one needs multiple processors/cores or computing nodes\footnote{The terms processors and computing nodes will be used interchangeably in the rest of the paper.}. The first question one asks is how to divide the problem so as to run each sub-task in parallel.

Generally speaking, parallelization can be achieved using either \textit{task parallelization} or \textit{data parallelization}. In task parallelism, each computing node runs the same or different code in parallel. Whereas, in data parallelism, the input data is divided across the computing nodes and the same code processes the data elements in parallel. Data parallelism is simpler to implement, as well as being the more appropriate approach in most astronomical data processing applications, and this paper deals only with it.

Considering a system with N processors or computing nodes, the speedup that can be achieved (compared to 1 processor) can be given as:

			\begin{equation} \label{eq:speedup}
				S = \frac{T_1}{T_N},
			\end{equation}

where $T_1$ and $T_N$ are the code runtime for one and N processors respectively. $T_N$ depends not only on the number of computing nodes but also on the fraction of code that is serial. The total runtime of the parallel code using N processors can be expressed using Amdahl's law \citep{amdahl_validity_1967}:

			\begin{equation} \label{eq:runtime}
				 T_N = T_S + \frac{T_P}{N} + T_{sync}
			\end{equation}

where $T_S$ is the execution time of the serial fraction of the code, $T_P$ is the runtime of code that can be parallelized, and $T_{sync}$ is the time for synchronization (I/O operations etc.). The efficiency of the parallel code execution depends a lot on how optimized the code is, i.e. the lower the fraction of serial code, the better. If we ignore synchronization time, theoretically unlimited speedup can be achieved as $N\to\infty$ by converting the serial code to completely parallel code. More realistically, $T_{sync}$ can be modelled as $K * ln(N)$, where N is the number of processors and K is a synchronization constant \citep{gove_multicore_2010}. This means that at a particular process count, the performance gain over serial code will start decreasing. Minimization of Equation (\ref{eq:runtime}) gives:

			\begin{equation}\label{eq:ncpus}
				N = \frac{T_P}{K}
			\end{equation}

This means that the value of N for which the parallel code scales is directly proportional to the fraction of code that is parallel and inversely proportional to synchronization. In other words, by keeping N constant, one can achieve better performance by either increasing the fraction of parallel code or decreasing the synchronization time, or both.

We have used multiprocessing instead of multithreading to achieve parallelism. There is a very basic difference between threads and processes. \textit{Threads} are code segments that can be scheduled by the operating system. On single processor machines, the operating system gives the illusion of running multiple threads in parallel but in actuality it switches between the threads quickly (time division multiplexing). But in the case of multicore machines, threads run simultaneously on separate cores. Multiple processes are different from multiple threads in the sense that they have separate memory and state from the master process that invokes them (multiple threads use the same state and memory).

The most popular languages for parallel computing are C, C++ and FORTRAN. MPI as well as OpenMP protocols have been  developed for these three languages. But wrappers or software implementations do exist to support interpreted languages like Python, Perl, Java etc. As mentioned in the introduction, the target audience of this paper is astronomers using Python as their language of choice, and/or IRAF. Although much more optimized and faster-executing parallel code can be written in FORTRAN, C or any other compiled language, the main objective here is to optimize astronomer's time. The speed gain with compiled code comes at the cost of longer development time. The secondary objective is \textit{code reuse} i.e. using the existing Python code and/or IRAF tasks to parallelize the problem (wherever it is feasible).

\section{Python Multiprocessing}
\label{python_multiprocessing}
Python supports both multi-threading and multi-processing programming. The threads in Python are managed by the host operating system i.e. scheduling and switching of the threads is done by the operating system and not by the Python interpreter. Python has a mechanism called the Global Interpreter Lock (GIL) that generally prevents more than one thread running simultaneously, even if multiple cores or processors are available \citep{python_software_foundation_python/c_2012}. This results in only one thread having exclusive access to the interpreter resources, or in other words resources are ``locked'' by the executing thread. The running thread releases the GIL for either I/O operations or during interpreter periodic checks (by default after every 100 interpreter ticks or bytecode instructions) \citep{beazley_python_2006}. The waiting threads can run briefly during this period. This unfortunately affects the performance of multi-threaded applications and for CPU bound tasks, the execution time may be actually higher than serial execution. The performance deteriorates further on the multicore machines as the Python interpreter wants to run a single thread at a time whereas the operating system will schedule the threads simultaneously on all the available processor cores.

This is only true for the CPython implementation; PyPy\footnote{Just-in-time (JIT) compilation implementation}, Jython\footnote{Python implementation for Java virtual machine}, and IronPython\footnote{Python implementation for .NET framework} do not prevent running multiple threads simultaneous on multiple processor cores. Jython and IronPython use an  underlying threading model implemented in their virtual machines. But the default Python implementation on most operating systems is CPython and therefore the rest of this paper assumes the CPython implementation. In addition, many of the scientific tools are only available for CPython. Which is another reason why not many in scientific programming use these alternative python distributions.

A better option to get parallel concurrency is to use Python's native \textit{multiprocessing} module. Other standalone modules for parallelizing on shared memory machines include Parallel Python, pyLinda, and pyPastSet. Python multiprocessing and Parallel Python can also be used on a cluster of machines.

Another parallelizing option for distributed memory machines is message passing. A Python MPI implementation or wrappers (eg. PyCSP \citep{Vinter09pycsprevisited}, mpi4py \citep{dalcin_2008}, pupyMPI  \citep{bromer_2011}, and Pypar \citep{nielsen_2003}) can be used for this purpose. Parallelization can also be achieved by vectorizing the tasks using NumPy. Vectorization is an efficient and optimized way of replacing explicit iterative loops from the Python code. However, not all the operations can be parallelized in Numpy/SciPy \footnote{Refer to http://www.scipy.org/ParallelProgramming for more details}.

We have used the native \textit{multiprocessing} module and the standalone \textit{Parallel Python} module to achieve parallelization. For comparison purposes, we have implemented parallel code for four astronomy routines.

The \textit{multiprocessing} module is part of Python 2.6 and onwards, and backports exist for versions 2.4 and 2.5\footnote{More details on http://pypi.python.org/pypi/multiprocessing}. \textit{Multiprocessing} can also be used with a cluster of computers (using the multiprocessing \textit{Manager} object), although the implementation is not trivial. This paper deals only with shared memory or symmetric multiprocessing (SMP) machines, although detailed information about computer clusters for astronomical data processing can be found elsewhere\footnote{One such document can be found on our website - http://astro.nuigalway.ie/staff/navtejs}.

A few approaches exist in the Python \textit{multiprocessing} library to distribute the workload in parallel. In this paper we will be considering two main approaches - a pool of processes created by the \textit{Pool} class, and individual processes spawned by the \textit{Process} class. The \textit{Parallel Python} module uses inter-process communication (IPC) and dynamic load balancing to execute processes in parallel. Code implementation using these three approaches is discussed in detail in the following sub-sections.

\subsection{The Pool/Map Approach}
Out of the two \textit{multiprocessing} approaches, this is the simplest to implement. The \textit{Pool/Map} approach spawns a pool of worker processes and returns a list of results. In Python functional programming, a function can be applied to every item iterable using the built-in \textit{map} function. For example, instead of running an iterative loop, the \textit{map} function can be used:

\begin{center}
	\begin{lstlisting}[label=lst:iter,caption=Example Python iterative function]
		# Iterative function
		def worker( indata ):
			...
			return result

		# Input dataset divided into chunks
		lst = [ in1, in2, ... ]

		# Loop over lst items and append results
		results = []
		for item in lst:
			results.append( worker( item ) )
	\end{lstlisting}
\end{center}

\begin{center}
	\begin{lstlisting}[label=lst:map,caption=Python map function]
		# Iterative function
		def worker( indata ):
			...
			return result

		# Input dataset divided into chunks
		lst = [ in1, in2, ... ]

		# Iteratively run func in serial mode
		results = map( worker, lst )
	\end{lstlisting}
\end{center}

The \textit{map} function is extended to the \textit{multiprocessing} module and can be used with the \textit{Pool} class to execute worker processes in parallel, as depicted in Listing \ref{lst:pool_map}.

\begin{center}
	\begin{lstlisting}[label=lst:pool_map,caption=Pool/Map multiprocessing implementation]
		# Import multiprocessing module
		import multiprocessing as mp

		# Get number of processors on the machine
		# or manually enter required number of processes
		ncpus = mp.count_cpus()

		# Define pool of ncpus worker processes
		pool = mp.Pool( ncpus )

		# Start ncpus pool of worker processes in parallel
		# output is appended to results python list
		results = pool.map( worker, lst )
	\end{lstlisting}
\end{center}

The \textit{import} command includes the \textit{multiprocessing} module in the routine, the \textit{count\_cpus} method gets the number of processors or cores on the machine, the \textit{Pool} class creates a pool of \textit{ncpus} processes, and \textit{Pool's map} method iterates over the input element list in parallel, and maps each element to the \textit{worker} function. The number of worker processes spawned can be more than the number of cores on the machine but as we will see in Section \ref{examples}, best performance is achieved when the number of processes is equal to the number of physical processor cores or the total number of concurrent threads.

\subsection{The Process/Queue Approach}
The Pool/Map approach allows only one argument as an input parameter to the calling function. There are two ways to send multiple arguments: pack arguments in a python list or a tuple, or use the \textit{process} class in conjunction with a \textit{queue} or \textit{pipe}. Although a process can be used without queues and pipes, it is good programming practice to use them\footnote{Python documentation suggests to avoid synchronization locks and instead use the queue or the pipe (http://docs.python.org/library/multiprocessing.html\#programming-guidelines/)}. Two FIFO (First In, First Out) queues are created - one for sending input data elements and another for receiving output data. Parallel worker processes are started using the \textit{Process} class and smaller chunks of input data are put on the send queue for processing. Each worker process picks the next data chunk in the queue after processing the previous chunk. The output result is put on the receive queue, and then read at the end for post-processing.

An example Python code listing for the Process/Queue approach is shown below:

	\begin{lstlisting}[label=lst:process,caption=Process/Queue multiprocessing implementation]
		# Import multiprocessing module
		import multiprocessing as mp

		# Worker function
		# iter is standard python built-in function
		def worker( s_q, r_q, arg1, arg2, ... ):
			for value in iter( s_q.get, `STOP` ):
				...
				r_q.put( result )

		# Get number of cores on the machine
		ncpus = mp.count_cpus()

		# Create send and receive queues
		send_q = mp.Queue()
		recv_q = mp.Queue()

		# Start ncpus number of processes
		for i in range( ncpus ):
			mp.Process( target = worker, args = ( send_q, recv_q, arg1, arg2, ... ) )

		# Put input data chunks on send queue
		# indata is python list of input data set,
		# which is already divided into smaller chunks
		for chunk in indata:
			send_q.put( chunk )

		# Get output from receive queue
		results = []
		for i in range( len( indata ) ):
			results.append( recv_q.get() )

		# Stop all the running processes
		for i in  range( ncpus ):
			send_q.put( `STOP` )
	\end{lstlisting}

The code is self-explanatory but the main point to notice is the code related to stopping the running processes. \textit{STOP} or any other value can be put in the send queue to stop the processes, as the worker function reads from the queue until it encounters \textit{STOP}. We have found that in certain conditions, the Process/Queue approach performs better than the Pool/Map approach, as shown in Section \ref{examples}.

\subsection{Parallel Python Approach}
Parallel Python is an open source cross-platform module for parallelizing python code. It provides dynamic computation resource allocation as well as dynamic load balancing at runtime. In addition to executing programs in parallel on Symmetric multiprocessing (SMP) machines, it can also be used on clusters of heterogeneous multi-platform machines \citep{vanovschi_parallel_2013}.

Processes in Parallel Python run under a job server. The job server is started locally (or remotely if running on a cluster of machines) with the desired number of processes (ideally equal to the number of processor cores). A very basic code template is shown below:

	\begin{lstlisting}[label=lst:pp,caption=Parallel Python implementation]
		# Import Parallel Python module
		import pp

		# Parallel Python worker function
		def worker( indata ):
			...
			return result

		# Create an empty tuple
		ppservers = ()

		# Either manually set the number of processes or
		# default to the number of cores on the machine
		if ncpus:
			job_server = pp.Server( int(ncpus), ppservers = ppservers )
		else:
			job_server = pp.Server( ppservers = ppservers )

		# Divide data into smaller chunks for better
		# performance (based on the scheduler type)
		chunks = getchunks( infile, job_server.get_ncpus(), scheduler )

		# Start the worker processes in parallel
		jobs = []
		for value in chunks:
			indata = ( arg1, arg2, ...  )
			jobs.append( job_server.submit( worker, (indata,), (func1,func2,...), (mod1,mod2,...) ) )

		# Append the results
		results = []
		for job in jobs:
			results.append( job())
	\end{lstlisting}

The number of processes (\textit{ncpus}) is passed to the program as user input, or defaulted to the number of cores on the machine. The input data is divided into smaller chunks for better load balancing. The \textit{Parallel Python} job server starts the worker processes for parallel execution. At the end of the execution, results are retrieved from the processes. The parameters to the job server's submit method are the worker function, its arguments, and any other function or module used by the worker function.

\section {Benchmarking}
\label{examples}

To benchmark the parallel processing approaches described in the previous section, three different kinds of astronomical problems, of varied complexity, were parallelized. Three machines of different configuration were used to benchmark the code. The hardware and software configuration of the test machines is listed in Table \ref{tab:machines}.

\begin{table}[h]
\centering
	\def1.5{1.5}
	{\footnotesize
	\begin{tabular}{ | p{1.0cm} | p{2.1cm} | p{1.0cm} | p{2.0cm} | }
		\hline
		\multicolumn{1}{| c}{\textbf{Machine}} & \multicolumn{1}{| c |}{\textbf{Processor}} & \multicolumn{1}{| c |}{\textbf{Memory}}& \multicolumn{1}{| c |}{\textbf{Operating System}} \\
		\hline
		\hline
		Homebuilt &  AMD Phenom II X4 B60 quad core processor @3.4GHz & 4 GB @1066 MHz & Ubuntu 11.10 32-bit. Linux Kernel 3.0.0-16-generic-pae \\
		\hline
		Dell Studio XPS & Intel Core i7 920 quad core processor (8 threads) @2.67GHz & 6 GB @1066 MHz &  Ubuntu 12.10 32-bit. Linux Kernel 3.5.0-22-generic \\
		\hline
		iMac 21.5 inch & Intel Core i5 I5-2400S quad core processor @2.5GHz & 4 GB @1333 MHz & Mac OS X 10.8.1 64-bit. Darwin 12.1.0 \\
		\hline
	\end{tabular}}
	\caption{Hardware and software configuration of the SMP machines used for benchmarking the parallel code.}
	\label{tab:machines}
\end{table}

The homebuilt machine was over-clocked to 3.51 GHz and was running the Ubuntu 11.10 operating system (OS). The Dell Studio XPS was running the same OS but as a guest OS in a VirtualBox\footnote{VirtualBox is open source virtualization software. More details on https://www.virtualbox.org/} virtual machine on a Windows 7 host. Out of the 6 GB of RAM on the Dell machine, 2 GB was allocated to the guest OS. The iMac was running Mac OS X Mountain Lion. For astronomical data and image processing, existing routines from the ESO Scisoft 7.6\footnote{ESO Scisoft software package is a collection of astronomical utilities distributed by European Southern Observatory} software package were used. This version of Scisoft is using Python 2.5 and therefore the python \textit{multiprocessing} backport was separately installed. The latest version of Scisoft (version 7.7 released in March 2012) has been upgraded to Python 2.7 and therefore does not require separate installation of the \textit{multiprocessing} module. The iMac machine was using the latest version of Scisoft.

All of our benchmarking examples concern a class of parallel work flow known as \textit{Embarrassingly Parallel} problems. In simple terms this means that the problem can be easily broken down into components to be run in parallel. The first astronomy routine is a parallel implementation of coordinate transformation of the charge-coupled device (CCD) pixel to sky coordinates (RA and DEC), and vice-versa, for Hubble Space Telescope (HST) images, for a large number of input values. The second routine parallelized a Monte Carlo completeness test. The third routine is parallel implementation of sub-sampled deconvolution of HST images with a spatially varying point spread function (PSF). These routines are described in the following sub-sections. They are freely available and can be downloaded from our website\footnote{http://astro.nuigalway.ie/staff/navtejs}.

\subsection{PIX2SKY and SKY2PIX}
\label{pix2sky}
The STSDAS\footnote{Space Telescope Science Data Analysis System} package for IRAF includes the routines \textit{xy2rd} and \textit{rd2xy} to transform HST CCD image pixel coordinates to sky coordinates, and vice-versa. These tasks can only process one coordinate transformation at a time. Running them serially, or even in parallel, to process hundreds to thousands of transformations (e.g. star coordinate transformations in massive star clusters) is not efficient, as it will be performing the same expensive FITS header keyword reads on each call. Non-IRAF routines to transform lists of coordinates do exist, but they default to serial processing. Two such routines (\textit{xy2sky} and \textit{sky2xy}, implemented in C) are part of the WCSTools\footnote{More details on http://tdc-www.harvard.edu/wcstools/} software. A pure Python implementation exists in the \textit{pywcs} module, which is part of the \textit{astropy} package\footnote{Refer to http://www.astropy.org/ for more details}.

As these IRAF routines are not lengthy, they can easily be re-written for multicore machines to process a large input dataset in parallel. We have implemented two tasks - PIX2SKY (based on \textit{xy2rd}) and SKY2PIX (based on \textit{rd2xy}) -  in Python, using both the \textit{multiprocessing} and \textit{Parallel Python} modules. These routines read input files with either [X,Y] pixel coordinates (PIX2SKY routine) or [RA, DEC] values (SKY2PIX routine), and output transformed coordinates. We have used the PyFITS\footnote{STScI's python module for working with FITS files} module from the Space Telescope Science Institute (STScI) for handling FITS images.

The speedup factor (as defined in Section \ref{pdp}) for PIX2SKY and SKY2PIX is plotted against the number of processes in Figure \ref{fig:fig1}. For this benchmarking, one million input coordinates were fed into the \textit{Parallel Python} based transformation modules with guided scheduling.

\begin{figure*}[!ht]
	\centering
		\includegraphics[width=0.76\linewidth]{Fig1}
		\caption{Coordinate transformation benchmark, using the Parallel Python approach with a guided scheduler. (a) PIX2SKY  and (b) SKY2PIX speedup on the three test machines. Data points are the average of 50 runs. As expected, maximum speedup occurs when the number of processes is equal to the number of physical cores on the machine. Of course, load balancing and the serial to parallel code fraction also influence the speedup.}
		\label{fig:fig1}
\end{figure*}

Best performance was achieved when the number of processes was equal to the number of physical cores on the machine. The Intel Core i7 based machine showed better speedup than the AMD Phenom based machine. This is because Intel Core i7 processors use hyper-threading technology\footnote{Proprietary technology of Intel Corporation to allow multiple threads to run on each core} and have 2 threads per core. Theoretically, we would have expected close to eight-fold speedup on the Intel Core i7 quad-core processor (with hyper-threading), but bottlenecks like I/O operations restrict higher performance gains (keeping the fraction of code running in parallel constant). As the number of processes increases beyond the number of cores, the speedup factor is almost flat. This is a result of dynamic load balancing in Parallel Python, which is not the case for the Process/Queue approach (as we will see in Section \ref{mmp}).

Another interesting point regarding Figure \ref{fig:fig1} is the somewhat inferior performance of Core i5 processor compared to the other two quad core processors. We could not do a direct comparison between the Core i5 processor and other two processors as by default \textit{Turbo Boost}\footnote{Proprietary technology of Intel Corporation to run processors above their base frequency} and \textit{Speed Step}\footnote{Refer to http://en.wikipedia.org/wiki/SpeedStep for more details} are turned on in the iMac machine (and cannot be switched off). For the other two processors - \textit{Speed Step technology} was turned off on the Core i7 processor and \textit{Cool'n'Quiet}\footnote{Refer to http://www.amd.com/us/products/technologies/cool-n-quiet/Pages/cool-n-quiet.aspx for more details.} was switched off on the AMD machine to prevent CPU throttling.

\subsection{Completeness Test}
In more complex or lengthy problems, it makes much more sense to reuse the existing tasks or optimized serial codes, rather than re-writing code as we did in Section \ref{pix2sky}. A good example is a completeness test - the method to determine the detection efficiency of different magnitude stars in images. It is a Monte Carlo class of algorithm, i.e. it involves repeated random execution. The basic idea behind the method is to add artificial stars of varied magnitudes to random positions within the image, and then determine their recovery rate as a function of magnitude. For the test to be statistically relevant, an average of a few hundred random iterations of modified images is taken.

To reuse the existing code, the \textit{addstar} task in the DAOPHOT package of IRAF was used to add artificial stars to the image under question and the \textit{daofind} and \textit{phot} tasks in DAOPHOT were used to detect and match the added stars. One way to achieve parallelism in this case is to run multiple iterations in parallel on the available computing nodes, where each node gets a complete image.

\begin{figure*}[!ht]
	\centering
		\includegraphics[width=0.76\textwidth]{Fig2}
		\caption{HST WFPC2 co-added image of the globular cluster M71 (NGC 6838) in the F555W filter, used for benchmarking the completeness routine. The test was performed on a 512$\times$512 image section (lower left). This image plus 50 artificial stars between $14^{th}$ and $28^{th}$ magnitude, generated in one of the Monte Carlo iterations, is shown in the lower right.}
		\label{fig:fig2}
\end{figure*}

For the benchmark, we used the reduced and co-added HST WFPC2\footnote{Wide Field Planetary Camera 2} (chip PC1) image of galactic globular star cluster M71 (NGC 6838) in the F555W filter (shown in Figure \ref{fig:fig2}). The completeness test was performed on a 512$\times$512 pixel uncrowded section of the image with $14^{th} - 28^{th}$ magnitude stars in each iteration. Fifty stars (a sufficiently small number to avoid changing the star density appreciably) were added randomly to the image section (shown in Figure \ref{fig:fig2}), and 100 iterations per magnitude interval were run. As in the previous benchmark, we used the Parallel Python approach with guided scheduler.

\begin{figure*}[!ht]
	\begin{minipage}[c]{0.5\linewidth}
		\subfigure[]{\label{fig:fig3a}\includegraphics[width=1\linewidth]{Fig3a}}
	\end{minipage}
	\begin{minipage}[c]{0.5\linewidth}
		\subfigure[]{\label{fig:fig3b}\includegraphics[width=1\linewidth]{Fig3b}}
	\end{minipage}
		\caption{(a) Detection completeness plot for the images in Figure \ref{fig:fig2} with artificial star magnitudes varying from 14.0 to 28.0 mag within 0.5 mag intervals; (b) Speedup achieved on the test machines as a function of the number of parallel processes. The Parallel Python approach with guided scheduler was used for benchmarking.}
\end{figure*}

In Figure \ref{fig:fig3a}, we plot the completeness test results, computed by averaging results from all the iterations, with a 0.5 magnitude bin interval. Figure \ref{fig:fig3b} shows that maximum speedup is achieved when the number of processes is equal to the number of physical cores, or the total number of threads (in the case of the Intel Core i7 machine). All three processors show close to 2$\times$ speedup with 2 spawned processes. After four processes, speedup flattens out for the AMD and Core i5 processors whereas it keeps on increasing for the Core i7 machine (although not as steeply as from 1 to 4 processes). This is explained by Equation \ref{eq:ncpus} - the number of processes is scaled on the parallel code fraction and synchronization time.

\subsection{Parallel Sub-Sampled Deconvolution}
Image deconvolution is an embarrassingly parallel problem, as image sections can be deconvolved in parallel and combined at the end. In addition to being under-sampled, HST detector point spread functions are spatially varying. To recover resolution lost to aberration and poor sampling in HST images, \citet{butler_deconvolution_2000} proposed an innovative sub-sampled deconvolution technique. We have implemented a parallel version of this technique.

\begin{figure*}[!ht]
\begin{center}
	\subfigure[]{\label{fig:fig4a}\includegraphics[width=0.52\linewidth]{Fig4a}}
	\hspace{20pt}
	\subfigure[]{\label{fig:fig4b}\includegraphics[width=0.43\linewidth]{Fig4b}}
\end{center}
	\caption{(a) HST WFPC2 PC1 coadded image of globular cluster NGC 6293 in the F814W filter. A normal sampled $4.6\mbox{$^{\prime\prime}$} \times 4.6\mbox{$^{\prime\prime}$}$ image section is shown in the upper left hand corner, and the 2$\times$ sub-sampled deconvolved section in the upper right hand corner; (b) Sub-sampled deconvolution benchmark. The AMD quad core performance levels out after four processes, whereas the Intel quad core achieves a speedup factor of almost 5 for eight processes. The Parallel Python approach with guided scheduler was used for benchmarking.}
\end{figure*}

To deconvolve HST images with a spatially varying PSF, we wrote a parallelized version of the sub-sampled image deconvolution algorithm. The Maximum entropy method (MEM) implementation in the STSDAS package was used for deconvolution. As it only uses a spatially invariant PSF, highly overlapping 256$\times$256 sub-images were deconvolved with the appropriate PSF for that position on the CCD. Deconvolved sub-images were reassembled to generate the final sub-sampled deconvolved image.

For benchmarking, we used a coadded HST WFPC2 PC1 chip image of the globular cluster NGC 6293. A spatially varying analytical PSF model was generated from the TinyTim\footnote{TinyTim is a point spread function modeling tool for HST instruments} PSF grid. The Parallel Python module with guided scheduler was used for benchmarking. The central region of NGC 6293, along with a high resolution section of the normal sampled image and sub-sampled deconvolved image, are shown in Figure \ref{fig:fig4a}. The speedup factor levels out close to 4 for the AMD machine, whereas it levels out at 5 for the Intel Core i7 machine (see Figure \ref{fig:fig4b}). In general, embarrassingly parallel problems provide the best speedup as a higher fraction of code is running in parallel.

\section{Discussion}
\label{discuss}

\subsection{Ease of Implementation}
As shown in Section \ref{python_multiprocessing}, parallelizing existing python serial code can be pretty straightforward for problems that can be easily broken down into smaller parts. This is especially true if the \textit{multiprocessing} Pool/Map approach is used in existing functional python code. Python includes excellent code profilers - \textit{cProfile} and \textit{Profile}. These, along with the \textit{pstats} module, can be used to optimize the parallel code as well as the serial code.

Astronomers using IRAF scripts now have another reason to move to PyRAF, and the python scripting language in general. The PyRAF command line interface allows execution of IRAF CL scripts, and also gives full flexibility and the power of the python language. STScI has a very useful PyRAF introductory tutorial\footnote{http://stsdas.stsci.edu/pyraf/doc.old/pyraf\_tutorial/} on their website. Another reason for using python is that it is an open source language, supported by community development, with most of the modules available for free. Python modules NumPy and SciPy comprise an extensive collection of numerical and scientific functions\footnote{Numerical Python (NumPy) and Scientific Python (SciPy) are non-standard Python modules}.

IRAF saves the task parameter values in global parameter files. This could lead to deadlock if same two tasks try to gain write access to the parameter file. This can be avoided in PyRAF by explicitly specifying all the parameters in the task, thus avoiding accessing the global parameter file.

\subsection{Load Balancing}
Load balancing in parallel computing is the distribution of the workload on computing nodes to optimize performance. It is an important issue to deal with while designing a parallel application. On multicore machines, all the cores will not perform identically as other activities and tasks are running concurrently. A parallel program will run as fast as the slowest core. Thus, the performance of a parallel program will be dictated by the slowest processor core. Therefore, efficient load balancing of the workload on the processor cores is very important. On shared memory machines, the OpenMP protocol has implemented four types of schedulers or load balancing routines - \textit{static}, \textit{guided}, \textit{dynamic} and \textit{runtime} \citep{chandra_parallel_2001}. On the same lines, we have implemented \textit{static} and \textit{guided} scheduler routines to slice large input datasets into smaller chunks and distribute them on the computing nodes. In the static scheduler, equal chunks of data are distributed on each computing node. In the guided scheduler, instead of distributing equal chunks in one go, the dataset is divided in much smaller chunks to provide better performance. These two schedulers were used in both the PIX2SKY and SKY2PIX routines. For more efficient load balancing, dynamic or runtime routines can be implemented.

In normal usage of both PIX2SKY and SKY2PIX, we read hundreds to thousands of input records. Sending large chunks of file data to computing nodes would result in a longer synchronization time. Instead, we send the starting and ending byte values of the file chunks, and actual file reading is done inside the worker process at each node. Example scheduler implementation code is shown below:

	\begin{lstlisting}[label=lst:load,caption=Scheduler implementation code]
		def getchunks( infile, ncpus, scheduler = `guided` ):
			# Based on scheduler, divide the input data element
			if scheduler == `static`:
				size = getsize( infile ) / ncpus
			else:
				size = getsize( infile ) / (ncpus * 20)

			# Open the input file. Display error and
			# exit if open fails
			try:
				ifile = open( infile )
			except:
				print >> sys.stderr, `Error : Not able to open `, infile, `. Exiting.`
				sys.exit( -1 )

			# Get starting and ending byte values for each chunk,
			# taking care to read the full line
			while 1:
				start = ifile.tell()
				ifile.seek(size, 1)
				s = ifile.readline()
				yield start, ifile.tell() - start
				if not s:
					break

			# Close the input file
			ifile.close()
    	\end{lstlisting}

In the case of the \textit{guided} scheduler, the number of records is divided into a large number (20 times the number of processes) of smaller chunks. The performance of the PIX2SKY routine with one million input records on our AMD quad core machine, with both the \textit{static} and \textit{guided} scheduler, is shown in Figure \ref{fig:fig5}. The Parallel Python approach was used, but we get the same results with the other two approaches also.

\begin{figure*}[!ht]
	\centering
	\includegraphics[width=0.8\linewidth]{Fig5}
	\caption{(a) Speedup and (b) Wall time for the PIX2SKY routine with different schedulers. The guided scheduler shows better performance than the static. Wall time is the total execution time for the routine. Data points are averaged over 100 runs. Program wall time on COTS machines depends on the other jobs and programs running. Error bars depict 1 standard deviation. The Parallel Python approach was used.}
	\label{fig:fig5}
\end{figure*}

The graph clearly shows a better performance for the guided scheduler. Therefore dividing work into smaller fragments is better for optimum performance of parallel programs.

\subsection{Multiprocessing Method Performance}
\label{mmp}
To compare the performance of the different multiprocessing methods introduced in Section \ref{python_multiprocessing}, we again took the PIX2SKY and SKY2PIX routines with one million input coordinates to be transformed. Our plots of run time (wall time) versus number of processes for the AMD quad core machine are shown in Figure \ref{fig:fig6a} and Figure \ref{fig:fig6b}.

\begin{figure*}[!ht]
	\begin{minipage}[c]{0.5\linewidth}
		\subfigure[PIX2SKY]{\label{fig:fig6a}\includegraphics[width=0.92\linewidth]{Fig6a}}
	\end{minipage}
	\hfill
	\begin{minipage}[c]{0.5\linewidth}
		\subfigure[SKY2PIX]{\label{fig:fig6b}\includegraphics[width=0.92\linewidth]{Fig6b}}
	\end{minipage}
	\begin{minipage}[c]{0.5\linewidth}
		\subfigure[Completeness Test]{\label{fig:fig6c}\includegraphics[width=0.92\linewidth]{Fig6c}}
	\end{minipage}
	\begin{minipage}[c]{0.5\linewidth}
		\subfigure[Sub-sampled Deconvolution]{\label{fig:fig6d}\includegraphics[width=0.92\linewidth]{Fig6d}}
	\end{minipage}
	\caption{Performance of different multiprocessing methods. Panels (a) and (b) depict the performance of our PIX2SKY and SKY2PIX routines on our AMD quad core machine respectively. Panel (c) depicts the performance of our completeness test and panel (d) that of our parallel sub-sampled deconvolution.  Data points are the average of 50 iterations for the PIX2SKY benchmark and 10 iterations for the completeness test and deconvolution. The Parallel Python, Pool and Process approaches show comparable performance for our completeness and sub-sampled deconvolution routines, whereas the Process/Queue approach performs better than both the Parallel Python and Pool/Map approaches for the PIX2SKY and SKY2PIX routines.}
\end{figure*}

For both PIX2SKY and SKY2PIX, the Process/Queue approach performs better than both the Pool/Map and Parallel Python approaches. However, Parallel Python scales nicely when the number of processes are more than number of physical cores. Although the Process/Queue performs better, implementing the Pool/Map method is much more straightforward.

For our routines using existing IRAF tasks - the completeness test and sub-sampled deconvolution - all three approaches have comparable performance. This is because the execution time of these routines is dictated by the performance of the underlying IRAF tasks (see Figure \ref{fig:fig6c} and Figure \ref{fig:fig6d}).

\subsection{Scalability and Portability}
Data parallelism using Python multiprocessing scales nicely with the number of processor cores, as shown in Section \ref{examples}. Our coordinate transformation code also scales nicely with the number of input data elements. As depicted in Figure \ref{fig:fig7}, the PIX2SKY routine scales linearly with the number of input data elements. It was benchmarked on an AMD quad core machine for 4 processes, using the Process/Queue multiprocessing method and varying the input data elements from 500 to 1 million. Similar scalability is also achieved for the SKY2PIX routine.

\begin{figure*}[!ht]
	\centering
		\includegraphics[width=0.6\linewidth]{Fig7}
		\caption{Scalability of our PIX2SKY routine with the number of input elements, for a fixed number of processes. The number of input coordinates was varied from 500 to 1 million. The benchmark was carried out on an AMD quad core machine with 4 parallel processes. The data points are the average of 50 iterations, with error bars corresponding to $1 \sigma$. The inset box is a close-up of the area near the origin. The Process/Queue approach was used with guided scheduler.}
		\label{fig:fig7}
\end{figure*}

As Python is a platform-independent interpreted language, the parallel code implementation is portable, i.e. it can be implemented on any of the Python-supported OS. In two of our examples, we have used IRAF tasks which can only be executed on Linux or Unix-like OS (e.g. Mac OS X), as IRAF is only available for these platforms. But astronomical data analysis tasks not requiring IRAF can be run on other supported platforms.

\section{Conclusions}
\label{conclude}
We have shown that moving to parallel astronomical data processing is not as daunting as most astronomers perceive. The open source Python programming language provides the necessary tools to implement parallel code on multicore machines. We used three different hardware configurations, three different parallelizing schemes or approaches, two different load balancing routines, and three different applications of varied complexity to demonstrate the ease of implementation and benefits of parallelizing data processing tasks. Although the emphasis was on the Python \textit{multiprocessing} module, results from the Parallel Python module were also presented. The Process/Queue approach performed better as a parallelizing scheme than both the Pool/Map and Parallel Python approaches. Parallel performance can be optimized by carefully load balancing the workload. Where there is no possibility of re-writing the code for parallel processing because of complexity or any other factor, the existing serial code can still be used to parallelize the problem (as shown in the completeness test and sub-sampled deconvolution tasks). While these are not the only or the most optimized methods to parallelize the code, the computational time savings are still very significant, even with these straightforward approaches. The cross-platform nature of Python makes the code portable on multiple computer platforms.

\section{Acknowledgements}
We gratefully acknowledge the support of Science Foundation Ireland (under award number 08/RFP/PHY1236). Based on observations made with the NASA/ESA Hubble Space Telescope in programs GO-8118 and GO-5366, obtained from the data archive at the Space Telescope Institute. STScI is operated by the association of Universities for Research in Astronomy, Inc. under the NASA contract NAS 5-26555. STSDAS, TABLES, PyRAF and PyFITS are products of the Space Telescope Science Institute, which is operated by AURA for NASA. We also thank the anonymous referees for comments and suggestions, that greatly improved the clarity of the article.

\bibliographystyle{model2-names}

redpajama_set_name: RedPajamaArXiv


Our office hours are 9:00AM - 4:00PM Monday thru Thursday And 9:00AM - 12:00pm on Fridays. For general inquiries please call Briana Linares at 661-362-3300, Briana.linares@canyons.edu.
The Community Education office is lcoated in the new Canyons Hall Builiding in Room 167 on the first floor at the Valencia College of the Canyons campus.


Had I created this post four days ago, I'm sure the tone would have been much less positive; but here we are four days calmer, four days wiser.
On Tuesday, after being with Dell for over 10 years, Mark was laid off. While the initial shock of it was a tough blow in so many ways, each day since has been better than the last. In fact, this has been one of the best weeks in a very long time. Mark is consistently happier than I've seen him in so, so long. While he is obviously concerned about what the future holds, he is coming to accept this new road before him with an open mind.
I really believe that he has been given a gift. Mark is an amazingly dedicated man, and worked hard to provide for his family despite being completely unfulfilled at the end of each day. I know that this is EXACTLY what he needed. This is the kick in the toukus he desperatley needed to seek out more...from life and from his career. What may come of it, I don't know, but I do know that this experience will be nothing but positive for our family, and I have no doubts that we will be just fine. We have ALL learned so much from his hard work and dedication, and will in turn continue learning in the weeks and months ahead.
Hey! Been there done that! You've got a great attitude about it, and that's what will get you through. It's a new beginning. It's exciting!
yes great attitude. I know he'll find something soon.


text:
Palermo é um bairro nobre da cidade argentina de Buenos Aires. Está localizado na região nordeste da cidade, sendo delimitado pelos bairros de: Belgrano ao norte, Almagro e Recoleta ao sul, Villa Crespo e Colegiales a oeste e pelo Rio de la Plata a leste. Possui uma área total de 15,9 km² (7 sq mi), sendo o maior bairro de Buenos Aires.

É um dos bairros mais turísticos da cidade devido aos Bosques de Palermo, cafés, restaurantes, discotecas, e o Zoológico de Buenos Aires. Destaca-se também pela grande quantidade de sedes de produtoras de cinema e TV, localizadas em Palermo Hollywood.

No bairro localiza-se o Buenos Aires Lawn Tennis Club, clube de tênis que é o anfitrião do ATP de Buenos Aires, torneio ATP de tênis jogado no saibro. O estádio principal, Horacio Billoch Caride Stadium, tem uma capacidade de 5.500 espectadores. O estádio já sediou a Copa Davis e a Fed Cup.

História
Há duas versões distintas sobre a origem do nome do bairro. Uma delas remete ao nome da abadia franciscana de "São Benedito de Palermo", existente até os dias atuais. São Benedito (1526 a 1589) e é um dos santos padroeiros complementares de Palermo, capital da Sicília na Itália. Na outra versão, mais popular e apoiada pelos jornalistas, a terra teria sido originalmente comprada por um italiano imigrante chamado "Juan Domingo Palermo" no final do século XVI, logo após a fundação de Buenos Aires em 1580. Futuramente Juan Manuel de Rosas, um político conservador, construiu uma residência de campo na área, que foi confiscada depois de sua queda do poder em 1851.

A área cresceu rapidamente durante o século XIX e, principalmente durante a presidência de Domingo Faustino Sarmiento, responsável pela criação do Jardim Zoológico de Buenos Aires e do "Parque Tres de Febrero", em 1874, e da Plaza Italia e do Palermo Race Track, em 1876.

Durante o século XX o bairro ganhou o Jardim Botânico de Buenos Aires (1902), o Aeroparque Jorge Newbery, vários clubes desportivos, o Jardim Japonês de Buenos Aires e o planetário Galileu Galilei.

Possui várias estações da linha D do Metrô de Buenos Aires, como: Bulnes , Scalabrini Ortiz, Plaza Italia, Palermo, Ministro Carranza, e Olleros (no limite com o bairro de Colegiales). Além disso, três linhas de transporte ferroviário suburbano passam pelo bairro: Retiro - José León Suárez (Mitre), Retiro - Tirgre (Mitre) e Retiro - Pilar (San Martin).

Atualidade
Palermo possui diversos setores (sub-bairros não oficiais):

 Palermo Chico ou Barrio Parque: É a área mais nobre do bairro. Apresenta mansões e residências de alto padrão, onde vive parte da classe-alta portenha.
 Palermo Viejo:  É a área mais antiga do bairro, onde viveram Jorge Luis Borges e Che Guevara. Historicamente foi uma área residencial popular. Abrigou muitos imigrantes vindos da Polônia, Armênia, Ucrânia e do Líbano. Porém as tradições das famílias espanholas e italianas, existentes a mais tempo na região, são refletidas nos restaurantes locais, igrejas, escolas e centros culturais.
 Palermo Soho: É uma pequena área de Palermo Viejo próxima à Plaza Serrano (oficialmente Plazoleta Cortázar). Abriga escritórios e lojas de moda e design, restaurantes, bares e cultura de rua.
 Palermo Hollywood: Surgiu em meados dos anos 1990 devido à grande quantidade de produtoras de TV, cinema e rádio instaladas em uma pequena região de Palermo Viejo. Atualmente, ele é mais conhecido pela concentração de restaurantes, discotecas, cafés e sua ativa vida noturna.
 Las Cañitas: No início do século XX era um reduto de cortiços, mas passou por um processo de gentrificação e desde então se tornou uma área de luxo. Apresenta diversos arranha-céus, restaurantes e bares, localizados ao lado do Campo de Pólo Argentino.
 Villa Freud: Localizada no em torno de Plaza Güemes, é uma zona residencial conhecida pela sua alta concentração de moradores psicólogos e psiquiatras, daí o seu nome que homenageia o fundador da psicanálise, Sigmund Freud.

redpajama_set_name: RedPajamaWikipedia


text:
JOIN GGHA
WHO IS GGHA
GLOBAL HEALTH ATL
ABOUT GLOBAL HEALTH ATL
GLOBAL HEALTH ATL LEADERSHIP
GLOBAL HEALTH ATL INITIATIVES
WOMEN IN GLOBAL HEALTH GA, USA
2020 GEORGIA GLOBAL HEALTH STUDY
GGHA & MEMBERS NEWS
GLOBAL HEALTH NEWS STREAM
PHEC
GLOBAL HEALTH RESOURCES
GEORGIA SCHOOLS
DISEASE SPECIFIC
GEORGIA HEALTHY CITIES
Secretary Price Appoints Brenda Fitzgerald, M.D., as CDC Director and ATSDR Administrator
Today, Health and Human Services Secretary Tom Price, M.D., named Brenda Fitzgerald, M.D., as the 17th Director of the Centers for Disease Control and Prevention (CDC) and Administrator of the Agency for Toxic Substances and Disease Registry (ATSDR).
"Today, I am extremely proud and excited to announce Dr. Brenda Fitzgerald as the new Director of the CDC," said Secretary Price. "Having known Dr. Fitzgerald for many years, I know that she has a deep appreciation and understanding of medicine, public health, policy and leadership—all qualities that will prove vital as she leads the CDC in its work to protect America's health 24/7. We look forward to working with Dr. Fitzgerald to achieve President Trump's goal of strengthening public health surveillance and ensuring global health security at home and abroad. Congratulations to Dr. Fitzgerald and her family."
Dr. Fitzgerald has been the commissioner of the Georgia Department of Public Health (DPH) and state health officer for the past six years. She replaces Dr. Anne Schuchat, who has been the acting CDC director and acting ATSDR administrator since January 20. Dr. Schuchat is returning to her role as CDC's principal deputy director.
"Additionally, I'd like to extend my deep appreciation and thanks to Dr. Anne Schuchat for her exemplary service as acting director of the CDC," said Secretary Price. "We thank Dr. Schuchat and her team for their dedication in our public health efforts to keep Americans safe and for their work to ensure a seamless transition. We look forward to continuing to work with Dr. Schuchat in her role as principal deputy director of CDC."
Dr. Fitzgerald, a board-certified obstetrician-gynecologist, has practiced medicine for three decades. As Georgia DPH Commissioner, Dr. Fitzgerald oversaw various state public health programs and directed the state's 18 public health districts and 159 county health departments. Prior to that, Dr. Fitzgerald held numerous leadership positions. She served on the board and as president of the Georgia OB-GYN Society and she worked as a health care policy advisor with House Speaker Newt Gingrich and Senator Paul Coverdell. She has served as a Senior Fellow and Chairman of the Board for the Georgia Public Policy Foundation.
Dr. Fitzgerald holds a Bachelor of Science degree in Microbiology from Georgia State University and a Doctor of Medicine degree from Emory University School of Medicine. She completed post-graduate training at the Emory-Grady Hospitals in Atlanta and held an assistant clinical professorship at Emory Medical Center. As a Major in the U.S. Air Force, Dr. Fitzgerald served at the Wurtsmith Air Force Strategic Air Command (SAC) Base in Michigan and at the Andrews Air Force Base in Washington, D.C.
Source: https://www.hhs.gov/about/news/2017/07/07/Secretary-Price-Appoints-Brenda-Fitzgerald-as-CDC-Director-and-ATSDR-Administrator.html
999 Peachtree St. NE c/o Georgia Bio Suite 1800
©2020-2021 Georgia Global Health Alliance. All rights reserved
Finfrock Web Design

redpajama_set_name: RedPajamaCommonCrawl


text:
Q: How to get multiple values in a list without using count in terraform? I am creating multiple resources using count in terraform.
for ex:
resource "aws_subnet" "rSubnetMGMT" {
  count = length(var.vletter)
  availability_zone = "${var.vRegion}${var.vletter[count.index]}"
  vpc_id     = aws_vpc.rVPCMGMT.id
  cidr_block = var.vSubnetMGMTCIDR
  map_public_ip_on_launch = "true"

  tags = {
    Name = "${var.vWorkloadShortCode}-mgmt-MGMT- ${var.vRegion}${var.vletter[count.index]}"
    SubnetType = "MGMT"

  }
}

here vletter = ["a","b","c"]
so this creates 3 subnets per availability zone
now I want to create an "aws_autoscaling_group" which requires a list of vpc_zone_identifier i.e. the subnet ids that I created
resource "aws_autoscaling_group" "rAutoScalingGroup" {
  count = lenght(var.vletter)
  max_size                  = var.vMaxNoofInstances
  min_size                  = var.vMinNoofInstances
  launch_configuration      = aws_launch_configuration.rLaunchConfiguration.name
  vpc_zone_identifier       = [aws_subnet.rSubnetMGMT[count.index].id ]
  metrics_granularity       = 1Minute
  enabled_metrics           = [GroupInServiceInstances]
  load_balancers = aws_elb.rLoadBalancer.name

  tag {
    Name                 = "${var.vInstanceShortNameBAS}-asg"
  }
}

but if I use count while creating the resource(aws_autoscaling_group) it will create multiple resources i.e. 3 different autoscaling groups for each subnet, but here I only want all the subnet ids that I created earlier. How can I achieve this without creating multiple resources?

A: You can use the splat operator: aws_subnet.rSubnetMGMT.*.id which will resolve to be the list of IDs of the subnets that were created.

redpajama_set_name: RedPajamaStackExchange


Searching for: researcher is "ventureone"
According to this research, valuations of US venture backed companies increased for the fifth consecutive quarter, reaching $13 million overall in the third quarter of 2004. This is the highest overall median premoney valuation since 2001 and an increase from the $11 million median posted in the third quarter of 2003.
382719F8 Click here to contact the authors.
According to this research, venture capital and private equity funds showed substantial activity in the third quarter of 2004 in both the US and Europe. In the US, 19 new venture capital funds raised a total of $3.20 billion. In Europe, 11 venture capital, private equity and buyout funds held final closes, raising a total of €8.49 billion.
80271870 Click here to contact the authors.
According to this research, in the second quarter 24 venture backed US companies completed initial public offerings (IPOs) which raised $1.3 billion, the most which has occurred in a single quarter since 2000. The researcher says this shows an increased appetite for IPOs of US venture backed companies, leading to a dramatic improvement in liquidity activity.
A82439BD Click here to contact the authors.
Continuing a trend of steady improvement for three consecutive quarters, this research finds that valuations of US venture backed companies rose in the first quarter of 2004. The overall median premoney valuation reached its highest level in more than two years at $13.7 million, up from $12.1 million in the fourth quarter of 2003.
A1233886 Click here to contact the authors.
According to this research, US venture capitalists have yet to invest a substantial portion of their funds, much of it earmarked for their existing portfolio companies. The so called venture capital overhang of US funds is estimated at $68 billion, with the majority of it committed from limited partners since 2000.
7B218051 Click here to contact the authors.
This research reveals that median pre-money valuations dropped slightly in Q4 2003, although the median valuation of information technology companies reached its highest level in two years. The overall median pre-money valuation for a venture backed company was $10.7 million, down from $12 million posted in the third quarter of the year.
74210785 Click here to contact the authors.
According to this research, in 2003, 21 US based venture-backed companies debuted in the public market, raising almost $1.4 billion. Despite the absence of any IPOs in the first quarter of 2003, the year picked up, closing with one more IPO than in 2002. But the double digit numbers of the past three years are still at dramatically low levels; from 1992-2000, the annual number of IPOs dropped under 100 only once.
69196927 Click here to contact the authors.
According to this resure, Venture backed companies received higher valuations in the third quarter of 2003. The overall median pre-money valuation climbed to $11.4 million, up from $8.7 million in the second quarter, and reached its highest level since 2001.
73192792 Click here to contact the authors.
This research asks if it matters whether a start up takes money from a large venture firm or a small venture firm? According to the report, the answer is a resounding yes.
63177020 Click here to contact the authors.
According to this research, valuations of venture backed companies continued to decrease slightly in the second quarter of 2003. The median pre-money valuation fell from $9.8 million in the first quarter of 2003 to $8.7 million in 2Q03, a range comparable to valuations in 1995.
25165783 Click here to contact the authors.


Happy Anniversary Garden Flag shows red roses on a piano and reads "live, laugh, love, happy anniversary" The roses and the ribbon they are tied with are embellished with embroidery to finish off this lovely flag. This flag by Premier designs measures 12 x 18 inches and has text that reads correctly from one side only. This flag can be personalized by checking the "yes to personalization" box before add this item to your cart. The personalization will appear on one side only and an additional fee does apply. This would make a great addition to any anniversary celebration.


text:
package com.optimalorange.cooltechnologies.ui;

import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.optimalorange.cooltechnologies.R;
import com.optimalorange.cooltechnologies.entity.Video;
import com.optimalorange.cooltechnologies.listener.OnRecyclerViewScrollListener;
import com.optimalorange.cooltechnologies.network.SearchRequest;
import com.optimalorange.cooltechnologies.network.VolleySingleton;
import com.optimalorange.cooltechnologies.util.Utils;
import com.umeng.analytics.MobclickAgent;

import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.LinkedList;
import java.util.List;

import me.zhanghai.android.materialprogressbar.MaterialProgressBar;

/**
 * 搜索页面
 *
 */
public class SearchActivity extends BaseActivity {

    private static final String CATEGORY_LABEL_OF_TECH = "科技";

    private String mYoukuClientId;

    private String mKeyWord;

    private int mPage = 1;

    private VolleySingleton mVolleySingleton;

    private RecyclerView mRecyclerView;

    private RecyclerView.Adapter mAdapter;

    private RecyclerView.LayoutManager mLayoutManager;

    private LinkedList<Video> mListVideos = new LinkedList<Video>();

    private MaterialProgressBar mProgressBar;

    /** 是否有正在获取Video */
    private boolean mIsQueryingVideos = false;

    private OnRecyclerViewScrollListener mScrollListener;

    private SearchRequest buildSearchVideosRequest() {
        SearchRequest.Builder builder = new SearchRequest.Builder()
                .setClient_id(mYoukuClientId)
                .setKeyword(mKeyWord)
                .setCategory(CATEGORY_LABEL_OF_TECH)
                .setPage(mPage)
                .setPeriod(SearchRequest.Builder.PERIOD.HISTORY)
                .setOrderby(SearchRequest.Builder.ORDER_BY.VIEW_COUNT)
                .setResponseListener(new Response.Listener<List<Video>>() {
                    @Override
                    public void onResponse(List<Video> videos) {
                        for (Video mVideo : videos) {
                            mListVideos.add(mVideo);
                            if (mAdapter != null) {
                                mAdapter.notifyDataSetChanged();
                            }
                        }
                        //为下一次请求获取Video翻页
                        mPage++;
                        mIsQueryingVideos = false;
                        mProgressBar.setVisibility(View.GONE);
                        if (videos.size() == 0) {
                            removeListener();
                            Toast.makeText(SearchActivity.this, getString(R.string.at_last),
                                    Toast.LENGTH_SHORT).show();
                        }
                    }
                })
                .setErrorListener(new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        error.printStackTrace();
                        mIsQueryingVideos = false;
                        mProgressBar.setVisibility(View.GONE);
                    }
                });

        return builder.build();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);

        mYoukuClientId = getString(R.string.youku_client_id);
        mVolleySingleton = VolleySingleton.getInstance(this);

        mProgressBar = (MaterialProgressBar) findViewById(R.id.progressbar);

        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setHasFixedSize(true);
        mLayoutManager = new GridLayoutManager(this, 2);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mAdapter = new MyAdapter(mListVideos, mVolleySingleton.getImageLoader());
        mRecyclerView.setAdapter(mAdapter);

        initListener();

        //处理搜索,当在actionbar上的SearchView输入完成点击搜索时
        // 系统会启动一个搜索请求,由本页面自身接收(singleTop)
        handleIntent(getIntent());
    }

    @Override
    protected void onNewIntent(Intent intent) {
        handleIntent(intent);
    }

    private void handleIntent(Intent intent) {
        /* 清除原有的搜索结果 */
        if (mListVideos.size() > 0) {
            mListVideos.clear();
            mAdapter.notifyDataSetChanged();
        }

        //搜索请求
        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            mKeyWord = intent.getStringExtra(SearchManager.QUERY);
            mVolleySingleton.addToRequestQueue(buildSearchVideosRequest());
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        MobclickAgent.onPageStart(getClass().getSimpleName());
    }

    @Override
    public void onPause() {
        MobclickAgent.onPageEnd(getClass().getSimpleName());
        super.onPause();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.menu_search, menu);

        SearchManager searchManager =
                (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView =
                (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
        searchView.setSearchableInfo(
                searchManager.getSearchableInfo(getComponentName()));

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        return super.onOptionsItemSelected(item);
    }

    private void initListener() {
        mScrollListener = new OnRecyclerViewScrollListener() {
            @Override
            public void onBottom() {
                super.onBottom();
                if (!mIsQueryingVideos) {
                    mIsQueryingVideos = true;
                    mProgressBar.setVisibility(View.VISIBLE);
                    mVolleySingleton.addToRequestQueue(buildSearchVideosRequest());
                }
            }
        };
        mRecyclerView.addOnScrollListener(mScrollListener);
    }

    private void removeListener() {
        if (mScrollListener != null && mRecyclerView != null){
            mRecyclerView.removeOnScrollListener(mScrollListener);
            mScrollListener = null;
        }
    }

    /**
     * 搜索结果适配器
     */
    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

        private LinkedList<Video> mVideos;

        private ImageLoader mImageLoader;

        public MyAdapter(LinkedList<Video> mVideos, ImageLoader mImageLoader) {
            this.mVideos = mVideos;
            this.mImageLoader = mImageLoader;
        }

        @Override
        public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                int viewType) {
            View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.list_item_video, parent, false);
            ViewHolder vh = new ViewHolder(v);
            return vh;
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, final int position) {
            //加载图片
            mImageLoader.get(mVideos.get(position).getThumbnail_v2(),
                    ImageLoader.getImageListener(holder.thumbnail,
                            R.drawable.ic_image_view_placeholder,
                            R.drawable.ic_image_view_placeholder));
            //显示播放时长
            holder.duration.setText(Utils.getDurationString(mVideos.get(position).getDuration()));
            //显示视频标题
            holder.title.setText(mVideos.get(position).getTitle());
            //显示播放次数(这里使用字符串资源格式化)
            holder.viewCount.setText(String.format(getString(R.string.view_count),
                    Utils.formatViewCount(mVideos.get(position).getView_count(),
                            SearchActivity.this)));

            holder.thumbnail.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    ShowVideoDetailActivity.start(
                            v.getContext(), mListVideos.get(position).getId());
                }
            });

        }

        @Override
        public int getItemCount() {
            return mVideos.size();
        }

        public class ViewHolder extends RecyclerView.ViewHolder {

            ImageView thumbnail;

            TextView duration;

            TextView title;

            TextView viewCount;

            public ViewHolder(View v) {
                super(v);
                thumbnail = (ImageView) v.findViewById(R.id.thumbnail);
                duration = (TextView) v.findViewById(R.id.duration);
                title = (TextView) v.findViewById(R.id.title);
                viewCount = (TextView) v.findViewById(R.id.view_count);
            }
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
// Author: jmaessen@google.com (Jan Maessen)

#ifndef NET_INSTAWEB_REWRITER_PUBLIC_IMAGE_REWRITE_FILTER_H_
#define NET_INSTAWEB_REWRITER_PUBLIC_IMAGE_REWRITE_FILTER_H_

#include <map>

#include "net/instaweb/rewriter/cached_result.pb.h"
#include "net/instaweb/rewriter/public/image.h"
#include "net/instaweb/rewriter/public/image_url_encoder.h"
#include "net/instaweb/rewriter/public/resource.h"
#include "net/instaweb/rewriter/public/resource_slot.h"
#include "net/instaweb/rewriter/public/rewrite_context.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_filter.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/rewriter/public/rewrite_result.h"
#include "net/instaweb/rewriter/public/server_context.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/printf_format.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/html/html_element.h"
#include "pagespeed/kernel/http/content_type.h"
#include "pagespeed/kernel/http/image_types.pb.h"
#include "pagespeed/kernel/util/url_segment_encoder.h"

namespace net_instaweb {

class Histogram;
class Statistics;
class TimedVariable;
class Variable;
class WorkBound;

enum InlineResult {
  INLINE_SUCCESS,
  INLINE_UNSUPPORTED_DEVICE,
  INLINE_NOT_CRITICAL,
  INLINE_NO_DATA,
  INLINE_TOO_LARGE,
  INLINE_CACHE_SMALL_IMAGES_UNREWRITTEN,
  // Image should not be inlined because it is part of a responsive image.
  INLINE_RESPONSIVE,
  INLINE_INTERNAL_ERROR,
};

// Identify img tags in html and optimize them.
// TODO(jmaessen): Big open question: how best to link pulled-in resources to
//     rewritten urls, when in general those urls will be in a different domain.
class ImageRewriteFilter : public RewriteFilter {
 public:
  typedef std::map<GoogleString, AssociatedImageInfo> AssociatedImageInfoMap;

  // Statistic names:
  static const char kImageNoRewritesHighResolution[];
  static const char kImageOngoingRewrites[];
  static const char kImageResizedUsingRenderedDimensions[];
  static const char kImageRewriteLatencyFailedMs[];
  static const char kImageRewriteLatencyOkMs[];
  static const char kImageRewriteLatencyTotalMs[];
  static const char kImageRewritesDroppedDecodeFailure[];
  static const char kImageRewritesDroppedDueToLoad[];
  static const char kImageRewritesDroppedMIMETypeUnknown[];
  static const char kImageRewritesDroppedNoSavingNoResize[];
  static const char kImageRewritesDroppedNoSavingResize[];
  static const char kImageRewritesDroppedServerWriteFail[];
  static const char kImageRewritesSquashingForMobileScreen[];
  static const char kImageRewrites[];
  static const char kImageWebpRewrites[];
  static const char kImageWebpFromGifFailureMs[];
  static const char kImageWebpFromGifSuccessMs[];
  static const char kImageWebpFromGifTimeouts[];
  static const char kImageWebpFromJpegFailureMs[];
  static const char kImageWebpFromJpegSuccessMs[];
  static const char kImageWebpFromJpegTimeouts[];
  static const char kImageWebpFromPngFailureMs[];
  static const char kImageWebpFromPngSuccessMs[];
  static const char kImageWebpFromPngTimeouts[];
  static const char kImageWebpOpaqueFailureMs[];
  static const char kImageWebpOpaqueSuccessMs[];
  static const char kImageWebpOpaqueTimeouts[];
  static const char kImageWebpWithAlphaFailureMs[];
  static const char kImageWebpWithAlphaSuccessMs[];
  static const char kImageWebpWithAlphaTimeouts[];

  // The property cache property name used to store URLs discovered when
  // image_inlining_identify_and_cache_without_rewriting() is set in the
  // RewriteOptions.
  static const char kInlinableImageUrlsPropertyName[];

  static const RewriteOptions::Filter kRelatedFilters[];
  static const int kRelatedFiltersSize;

  explicit ImageRewriteFilter(RewriteDriver* driver);
  virtual ~ImageRewriteFilter();
  static void InitStats(Statistics* statistics);
  static void Initialize();
  static void Terminate();
  static void AddRelatedOptions(StringPieceVector* target);
  virtual void StartDocumentImpl();
  virtual void EndDocument();
  virtual void RenderDone();
  virtual void StartElementImpl(HtmlElement* element) {}
  virtual void EndElementImpl(HtmlElement* element);
  virtual const char* Name() const { return "ImageRewrite"; }
  virtual const char* id() const { return RewriteOptions::kImageCompressionId; }
  virtual void EncodeUserAgentIntoResourceContext(
      ResourceContext* context) const;

  // Registers image information associated with a URL, for use by
  // experiment_collect_mob_image_info. Should be called from DOM-safe
  // context: the parser thread or a Render() method.
  void RegisterImageInfo(const AssociatedImageInfo& image_info);

  // Tries to extract information stored by the image rewrite filter
  // in *in, and to store it in *out. Returns whether successful.
  //
  // The context is used to try to find a name for the image if it was
  // not optimized.
  static bool ExtractAssociatedImageInfo(const CachedResult* in,
                                         RewriteContext* context,
                                         AssociatedImageInfo* out);

  // Can we inline resource?  If so, encode its contents into the data_url,
  // otherwise leave data_url alone.
  InlineResult TryInline(bool is_html, bool is_critical,
      int64 image_inline_max_bytes, const CachedResult* cached_result,
      ResourceSlot* slot, GoogleString* data_url);

  // The valid contents of a dimension attribute on an image element have one of
  // the following forms: "45%" "45%px" "+45.0%" [45% of browser width; we can't
  // handle this] "45", "+45", "45px", "45arbitraryjunk" "45px%" [45 pixels
  // regardless of junk] Technically 0 is an invalid dimension, so we'll reject
  // those as well; note that 0 dimensions occur in the wild and Safari and
  // Chrome at least don't display anything.
  //
  // We actually reject the arbitraryjunk cases, as older browsers (eg FF9,
  // which isn't *that* old) don't deal with them at all.  So the only trailing
  // stuff we allow is px possibly with some white space.  Note that some older
  // browsers (like FF9) accept other units such as "in" or "pt" as synonyms for
  // px!
  //
  // We round fractions, as fractional pixels appear to be rounded in practice
  // (and our image resize algorithms require integer pixel sizes).
  //
  // Far more detail in the spec at:
  //   http://www.whatwg.org/specs/web-apps/current-work/multipage/
  //                  common-microsyntaxes.html#percentages-and-dimensions
  static bool ParseDimensionAttribute(const char* position, int* value);

  // Creates a nested rewrite for an image inside a CSS file with the given
  // parent and slot, and returns it. The result is not registered with the
  // parent.
  RewriteContext* MakeNestedRewriteContextForCss(
      int64 css_image_inline_max_bytes,
      RewriteContext* parent,
      const ResourceSlotPtr& slot);

  // Creates a nested rewrite for the given parent and slot and returns it. The
  // result is not registered with the parent.
  virtual RewriteContext* MakeNestedRewriteContext(RewriteContext* parent,
                                                   const ResourceSlotPtr& slot);

  // Update desired image dimensions if necessary. Returns true if it is
  // updated.
  bool UpdateDesiredImageDimsIfNecessary(
      const ImageDim& image_dim, const ResourceContext& resource_context,
      ImageDim* desired_dim);

  // Determines whether an image should be resized based on the current options.
  //
  // Returns the dimensions to resize to in *desired_dimensions.
  bool ShouldResize(const ResourceContext& context,
                    const GoogleString& url,
                    Image* image,
                    ImageDim* desired_dimensions);

  // Resize image if necessary, returning true if this resizing succeeds and
  // false if it's unnecessary or fails.
  bool ResizeImageIfNecessary(
      const RewriteContext* rewrite_context, const GoogleString& url,
      ResourceContext* context, Image* image, CachedResult* cached);

  // Allocate and initialize CompressionOptions object based on RewriteOptions
  // and ResourceContext.
  Image::CompressionOptions* ImageOptionsForLoadedResource(
      const ResourceContext& context, const ResourcePtr& input_resource,
      bool is_css);

  virtual const RewriteOptions::Filter* RelatedFilters(int* num_filters) const;
  virtual const StringPieceVector* RelatedOptions() const {
    return related_options_;
  }

  // Disable all filters listed in kRelatedFilters in options.
  static void DisableRelatedFilters(RewriteOptions* options);

 protected:
  virtual const UrlSegmentEncoder* encoder() const;

  virtual RewriteContext* MakeRewriteContext();

 private:
  class Context;
  friend class Context;

  // Helper methods.
  void InfoAndTrace(Context* context, const char* format, ...)
      INSTAWEB_PRINTF_FORMAT(3, 4);
  const ContentType* ImageToContentType(const GoogleString& origin_url,
                                        Image* image);
  void BeginRewriteImageUrl(HtmlElement* element, HtmlElement::Attribute* src);

  RewriteResult RewriteLoadedResourceImpl(Context* context,
                                          const ResourcePtr& input_resource,
                                          const OutputResourcePtr& result);

  // Returns true if it rewrote (ie inlined) the URL.
  bool FinishRewriteCssImageUrl(
      int64 css_image_inline_max_bytes,
      const CachedResult* cached, ResourceSlot* slot,
      InlineResult* inline_result);

  // Returns true if it rewrote the URL.
  bool FinishRewriteImageUrl(
      const CachedResult* cached, const ResourceContext* resource_context,
      HtmlElement* element, HtmlElement::Attribute* src, int image_index,
      HtmlResourceSlot* slot, InlineResult* inline_result);

  // Save image contents in cached if the image is inlinable.
  void SaveIfInlinable(const StringPiece& contents,
                       const ImageType image_type,
                       CachedResult* cached);

  // Populates width and height from either the attributes specified in the
  // image tag (including in an inline style attribute) or from the rendered
  // dimensions and sets is_resized_using_rendered_dimensions to true if
  // dimensions are taken from rendered dimensions.
  void GetDimensions(HtmlElement* element, ImageDim* page_dim,
                     const HtmlElement::Attribute* src,
                     bool* is_resized_using_rendered_dimensions);

  // Returns true if there is either a width or height attribute specified,
  // even if they're not parsable.
  bool HasAnyDimensions(HtmlElement* element);

  // Resizes low quality image. It further reduces the size of inlined low
  // quality image for mobile.
  void ResizeLowQualityImage(
      Image* low_image, const ResourcePtr& input_resource,
      CachedResult* cached);

  // Checks if image is critical to generate low res image for the given image.
  // An image is considered critical if it is in the critical list as determined
  // by CriticalImagesFinder. Images are considered critical if the platform
  // lacks a CriticalImageFinder implementation.
  bool IsHtmlCriticalImage(StringPiece image_url) const;

  // Persist a URL that would have be inlined to the property cache, if
  // options()->image_inlining_identify_and_cache_without_rewriting(). Returns
  // true if a PropertyValue was written.
  bool StoreUrlInPropertyCache(const StringPiece& url);

  bool SquashImagesForMobileScreenEnabled() const;

  void SaveDebugMessageToCache(const GoogleString& message,
                               Context* rewrite_context,
                               CachedResult* cached_result);

  scoped_ptr<WorkBound> work_bound_;

  // Statistics

  // # of images rewritten successfully.
  Variable* image_rewrites_;
  // # of images resized using rendered dimensions;
  Variable* image_resized_using_rendered_dimensions_;
  // # of images that we decided not to rewrite because of size constraint.
  Variable* image_norewrites_high_resolution_;
  // # of images that we decided not to serve rewritten. This could be because
  // the rewrite failed, recompression wasn't effective enough, the image
  // couldn't be resized because it had an alpha-channel, etc.
  // Note: This overlaps with most of the other image_rewrites_dropped_* vars.
  Variable* image_rewrites_dropped_intentionally_;
  // # of images not rewritten because we failed to decode them.
  Variable* image_rewrites_dropped_decode_failure_;
  // # of images not rewritten because the image MIME type is unknown.
  Variable* image_rewrites_dropped_mime_type_unknown_;
  // # of images not rewritten because the server fails to write the merged
  // html files.
  Variable* image_rewrites_dropped_server_write_fail_;
  // # of images not rewritten because the rewriting does not reduce the
  // data size by a certain threshold. The image is resized in this case.
  Variable* image_rewrites_dropped_nosaving_resize_;
  // # of images not rewritten because the rewriting does not reduce the
  // data size by a certain threshold. The image is not resized in this case.
  Variable* image_rewrites_dropped_nosaving_noresize_;
  // # of images not rewritten because of load.
  TimedVariable* image_rewrites_dropped_due_to_load_;
  // # of image squashing for mobile screen initiated. This may not be the
  // actual # of images squashed as squashing may fail or rewritten image size
  // is larger.
  TimedVariable* image_rewrites_squashing_for_mobile_screen_;
  // # of bytes saved from image rewriting (Note: This is computed at
  // rewrite time not at serve time, so the number of bytes saved in
  // transmission should be larger than this).
  Variable* image_rewrite_total_bytes_saved_;
  // Sum of original sizes of all successfully rewritten images.
  // image_rewrite_total_bytes_saved_ / image_rewrite_total_original_bytes_
  // is the average percentage reduction in image size.
  Variable* image_rewrite_total_original_bytes_;
  // # of uses of rewritten images (updating <img> src= attributes in HTML
  // or url()s in CSS).
  Variable* image_rewrite_uses_;
  // # of inlines of images (into HTML or CSS).
  Variable* image_inline_count_;
  // # of images rewritten into WebP format.
  Variable* image_webp_rewrites_;

  // # total number of milliseconds spent rewriting images since server start
  Variable* image_rewrite_latency_total_ms_;
  // Delay in microseconds of successful image rewrites.
  Histogram* image_rewrite_latency_ok_ms_;
  // Delay in microseconds of failed image rewrites.
  Histogram* image_rewrite_latency_failed_ms_;

  ImageUrlEncoder encoder_;

  // Counter to help associate each <img> tag in the HTML with a unique index,
  // for use in determining whether the image should be previewed.
  int image_counter_;

  // The set of inlinable URLs, populated as the page is parsed, if
  // image_inlining_identify_and_cache_without_rewriting() is set in the
  // RewriteOptions.
  StringSet inlinable_urls_;

  // Sets of variables and histograms for various conversions to WebP.
  Image::ConversionVariables webp_conversion_variables_;

  // The options related to this filter.
  static StringPieceVector* related_options_;

  std::map<GoogleString, AssociatedImageInfo> image_info_;
  // Used to figure out which RenderDone() call is the last one.
  bool saw_end_document_;

  DISALLOW_COPY_AND_ASSIGN(ImageRewriteFilter);
};

}  // namespace net_instaweb

#endif  // NET_INSTAWEB_REWRITER_PUBLIC_IMAGE_REWRITE_FILTER_H_


text:
Starbucks strengthens partner care with most significant investment in hourly wages
June 23, 2021 • 2 min read
Starbucks Canada adds to its total benefits package with commitment to paying above minimum wage
Starbucks has always believed in being a different kind of company – guided by Our Mission to inspire and nurture the human spirit. For nearly 50 years, Starbucks has been putting partner (employee) care at the centre of everything it does and has continued to invest in and share its success with partners.
Recently, the company raised wages for all its hourly partners by at least 5% – the most significant investment in retail hourly pay in Starbucks Canada's history – and has committed to paying partners above minimum wage across the country.
"Starbucks is proud to recognize the work of the more than 19,000 partners who wear the green apron every day," says Lori Digulla, senior vice president and general manager for Starbucks Canada. "This past year has forever changed us. We changed some plans, put other plans on hold and made some very difficult decisions. But what will always remain true at Starbucks is our commitment to sharing our success with our partners."
The retail wage increases are a significant step in the company's multi-year aspiration to make meaningful investments in pay and partner care. The changes took effect as of May 31, 2021 and offer at least a 5% increase for all baristas, shift supervisors and café attendants, and increase the starting hourly rate for partners to $0.25 above provincial minimum wages.
Starbucks has long held the belief that partners deserve competitive wages plus leading benefits that support their total wellbeing. All partners, even on their first day as a barista, are entitled to many of the supports and perks Starbucks offers such as free coffee or tea each week, free beverages on shift, a 30% partner discount, free Headspace app subscriptions, free access to LifeWorks and more. Additionally, all Starbucks partners who work a minimum of 20 hour per week are entitled to the company's vast array of benefits and perks including comprehensive medical and dental coverage, $5,000 mental health benefit, up to $1,000 in tuition reimbursement per year, RRSP Future Savings Plan, shares in the company through annual Beanstock grants and more.
Partner Care InfographicDownload
In maintaining the company's commitment, Starbucks continues to invest in its wide-ranging COVID-19 safety measures and supports like paid time-off to all store partners to get the COVID-19 vaccine, COVID-19 Sick Day Pay, Vaccine Side Effect Pay and Self-Isolation Pay.
Join the Starbucks Canada Pride Partner (employee) Network in the fight against HIV and commemorating the lives lost to AIDS-related illnesses on World Aids Day (December 1) and see how we can all take action to uplift our communities. The impact of AIDS is felt around the globe in communities and homes near and far. […]
Uplifting communities with every cup
The coffee you order helps support our commitment to farmers and their communities. From donating disease-resistant coffee trees to investing in sustainable agricultural practices and conserving water in coffee processing, we're working to empower communities and improve livelihoods. Here's how we're making a difference Positively empowering 1 million women and girls in coffee-, tea- and […]


The iCloud addin for Outlook and Windows, called iCloud Control Panel, adds an additional tree of folders to Outlook, which requires you either to move all your folders to the iCloud tree or to manually copy new or edited items to iCloud whenever you need it. This is where CodeTwo Sync for iCloud comes in. 8 Nov Your Apple device is configured with an iCloud account. You meet all of the system requirements listed on this site. iCloud Control Panel / iCloud for Windows is up and running with your credentials typed in. You are using CodeTwo Sync for iCloud with the default Outlook profile. My upgrade went smoothly, but Office Outlook would not open, citing Code Two as the culprit. Code Two is an Outlook add-in that syncs.
Disable the iCloud plug-in in Outlook: Remove the iCloud Add-in (Note: unchecking the checkbox doesn't help, you need to remove the. 15 Sep CodeTwo Sync for iCloud icon Allows you to synchronize folders between Outlook and iCloud automatically, including calendar and task. 12 May Windows: If you manage your personal contacts, calendars, and to-do items with Apple's iCloud service, CodeTwo Sync for iCloud helps you seamlessly integrate that data with Microsoft Outlook. Apple's own iCloud utility for Windows will add iCloud data to Outlook, but only as a secondary folder tree.
18 Jul I'm using iCloud with Outlook to synch my Contacts and Calendar with my iPhone and iPad. you can get iCloud to work again and get it to sync with Outlook as well. the iCloud application and looking in the top-right corner. Note 2: Attachment Save · CodeTwo Office Migration · Mail Merge Toolkit. 17 Jul Some users have reported iCloud not functioning correctly following an upgrade to Microsoft Office. Please make sure you download the latest. 5 Feb CodeTwo Sync for iCloud syncs Outlook folders with iCloud folders automatically synchronizes Outlook contacts, calendars and tasks with the. 26 Apr CodeTwo Sync for iCloud syncs Outlook folders with iCloud folders automatically synchronizes Outlook contacts, calendars and tasks with the. 15 Jan git; rsync; File synchronization/sharing services (iCloud, Google is a tool for source code control. git is not a general file synchronization tool.


Thanks to a unanimous vote of the Sarasota County Commission, two new members will serve on the county's Planning Commission.
On Jan. 25, the County Commission named Dr. Joseph Neunder, a Nokomis chiropractor, and Colin Pember of Siesta Key, a commercial real estate agent, to replace Planning Commission members John Ask and Philip Kellogg, whose terms had expired.
Neunder and Pember were among four people who had applied for the positions, a staff worksheet shows. The others were Robert Fletcher and Jordan Letschert, both of Sarasota. All four submitted their applications in May 2016, the worksheet notes. The County Commission also considered the same four people for Planning Commission seats in June and December 2016. In June of last year, the County Commission appointed Laura Benson of Venice, a real estate broker with Michael Saunders & Co.; in December 2016, it reappointed Kevin Cooper, president and CEO of the Greater Sarasota Chamber of Commerce.
Commissioner Alan Maio nominated both Neunder and Pember on Jan. 25. No other names were put forth.
The Planning Commission is considered the county's most influential advisory board; it also has proven a stepping-stone to seats on the County Commission.
In his application, Neunder wrote that he has owned his own clinic since 2010: Sarasota Spinal Mechanics on Beneva Road in Sarasota.
In 2010, he also made an unsuccessful bid for a seat on the Sarasota County School Board. In the three-way District 1 race — with incumbent Carol Todd and challenger Barry Woolf — Neunder garnered 21.63% of the vote to Todd's 61.87% and Woolf's 16.5%, according to records maintained by the Sarasota County Supervisor of Elections Office.
Neunder is a member of the board of the Sarasota YMCA's Evalyn Sadlier Jones Branch, a member of the board of the My Choice Pregnancy Center and a parishioner at Epiphany Cathedral in Venice, he wrote on his application.
He served as director of education and a dean at Meridian College in Sarasota from 2009 to 2010, he continued, in which capacity he often needed "to interact with local community businesses, in order to address academic and trade requirements/needs for the community. In conjunction with the information collected," he wrote, "and the help of my colleagues on campus, we were able to derive plausible working solutions to the need of the business community at large." That experience, he added, would be an asset to the Planning Commission.
In his application, Pember wrote that he has been an associate with Michael Saunders & Co. since November 2015. He also is a member of the Florida Bar.
"I have a deep interest in public service, law, development, and our natural resources," he wrote.
He has owned Centric Commercial Cleaning in Sarasota since March 2007, he noted in the resume he attached to his application.
From January 2009 to August 2010, he was a member of the board of FloridaOil.org in Sarasota, his resume says. In that capacity, he wrote, he researched and studied the Submerged Lands Act of 1953, worked with the Florida Legislature on an offshore oil-drilling bill and worked with the American Petroleum Institute and the Office of the U.S. Secretary of the Interior.
At the Thomas M. Cooley Law School in Lansing, Mich., he added in his resume, he took classes on zoning and land use planning, as well as on water law, property law, oil and gas law, contracts and constitutional law.
Fletcher is a real estate appraiser with his own firm, Fletcher Appraisal Services, in downtown Sarasota, his application shows. He served as a member and later chair of the City of Sarasota's Planning Board during a term from 2008 to 2010, his application says.
Letschert, who is co-manager and owner of TTJ Investments LLC, is a past general manager of Café L'Europe, and he owned the former Fred's Restaurant in Southside Village in Sarasota. "TTJ Investments initially concentrated on purchasing foreclosed residential properties, performing whatever repairs and renovation work were necessary, and selling them on the open market," he wrote in his application. Under his direction, the company has invested in five Crunch Gym franchises, he added, and he and his brother have acquired a partnership in the Galleon Resort and Marina in Key West.