text:
<!DOCTYPE html>

    <meta charset="utf-8">
    <title>date/js/date-format.js - YUI 3</title>
    <link rel="stylesheet" href="http://yui.yahooapis.com/3.9.1/build/cssgrids/cssgrids-min.css">
    <link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
    <link rel="stylesheet" href="../assets/css/main.css" id="site_styles">
    <link rel="shortcut icon" type="image/png" href="../assets/favicon.png">

            API Docs for: 3.17.2

APIs

Classes

Modules

            <input type="search" id="api-filter" placeholder="Type to filter APIs">

Anim

App

App.Base

App.Content

App.Transitions

App.TransitionsNative

AreaSeries

AreaSplineSeries

Array

ArrayList

ArraySort

AsyncQueue

Attribute

AttributeCore

AttributeEvents

AttributeExtras

AttributeLite

AttributeObservable

AutoComplete

AutoCompleteBase

AutoCompleteFilters

AutoCompleteHighlighters

AutoCompleteList

Axis

AxisBase

BarSeries

Base

BaseCore

BaseObservable

BottomAxisLayout

Button

ButtonCore

ButtonGroup

Cache

CacheOffline

Calendar

CalendarBase

CandlestickSeries

CanvasCircle

CanvasDrawing

CanvasEllipse

CanvasGraphic

CanvasPath

CanvasPieSlice

CanvasRect

CanvasShape

CartesianChart

CartesianSeries

CategoryAxis

CategoryAxisBase

CategoryImpl

Chart

ChartBase

ChartLegend

Circle

CircleGroup

ClassNameManager

ClickableRail

Color

Color.Harmony

Color.HSL

Color.HSV

ColumnSeries

ComboSeries

ComboSplineSeries

config

Console

ContentEditable

Controller

Cookie

CurveUtil

CustomEvent

DataSchema.Array

DataSchema.Base

DataSchema.JSON

DataSchema.Text

DataSchema.XML

DataSource.Function

DataSource.Get

DataSource.IO

DataSource.Local

DataSourceArraySchema

DataSourceCache

DataSourceCacheExtension

DataSourceJSONSchema

DataSourceTextSchema

DataSourceXMLSchema

DataTable

DataTable.Base

DataTable.BodyView

DataTable.BodyView.Formatters

DataTable.Column

DataTable.ColumnWidths

DataTable.Core

DataTable.HeaderView

DataTable.Highlight

DataTable.KeyNav

DataTable.Message

DataTable.Mutable

DataTable.Paginator

DataTable.Paginator.Model

DataTable.Paginator.View

DataTable.Scrollable

DataTable.Sortable

DataTable.TableView

Date

DD.DDM

DD.Delegate

DD.Drag

DD.Drop

DD.Scroll

Dial

Do

Do.AlterArgs

Do.AlterReturn

Do.Error

Do.Halt

Do.Method

Do.Prevent

DOM

DOMEventFacade

Drawing

Easing

EditorBase

EditorSelection

Ellipse

EllipseGroup

Escape

Event

EventFacade

EventHandle

EventTarget

Features

File

FileFlash

FileHTML5

Fills

Frame

Get

Get.Transaction

GetNodeJS

Graph

Graphic

GraphicBase

Gridlines

GroupDiamond

GroupRect

Handlebars

Highlight

Histogram

HistoryBase

HistoryHash

HistoryHTML5

HorizontalLegendLayout

ImgLoadGroup

ImgLoadImgObj

InlineEditor

Intl

IO

JSON

JSONPRequest

Lang

LazyModelList

LeftAxisLayout

Lines

LineSeries

Loader

MarkerSeries

Matrix

MatrixUtil

Model

ModelList

ModelSync.Local

ModelSync.REST

Node

NodeList

Number

NumericAxis

NumericAxisBase

NumericImpl

Object

OHLCSeries

Overlay

Paginator

Paginator.Core

Paginator.Url

Panel

Parallel

Path

PieChart

PieSeries

Pjax

PjaxBase

PjaxContent

Plots

Plugin.Align

Plugin.AutoComplete

Plugin.Base

Plugin.Button

Plugin.Cache

Plugin.CalendarNavigator

Plugin.ConsoleFilters

Plugin.CreateLinkBase

Plugin.DataTableDataSource

Plugin.DDConstrained

Plugin.DDNodeScroll

Plugin.DDProxy

Plugin.DDWindowScroll

Plugin.Drag

Plugin.Drop

Plugin.EditorBidi

Plugin.EditorBR

Plugin.EditorLists

Plugin.EditorPara

Plugin.EditorParaBase

Plugin.EditorParaIE

Plugin.EditorTab

Plugin.ExecCommand

Plugin.ExecCommand.COMMANDS

Plugin.Flick

Plugin.Host

plugin.NodeFocusManager

Plugin.NodeFX

plugin.NodeMenuNav

Plugin.Pjax

Plugin.Resize

Plugin.ResizeConstrained

Plugin.ResizeProxy

Plugin.ScrollInfo

Plugin.ScrollViewList

Plugin.ScrollViewPaginator

Plugin.ScrollViewScrollbars

Plugin.Shim

Plugin.SortScroll

Plugin.Tree.Lazy

Plugin.WidgetAnim

Pollable

Promise

Promise.Resolver

QueryString

Queue

RangeSeries

Record

Recordset

RecordsetFilter

RecordsetIndexer

RecordsetSort

Rect

Renderer

Resize

RightAxisLayout

Router

ScrollView

Selector

SeriesBase

Shape

ShapeGroup

Slider

SliderBase

SliderValueRange

Sortable

SplineSeries

StackedAreaSeries

StackedAreaSplineSeries

StackedAxis

StackedAxisBase

StackedBarSeries

StackedColumnSeries

StackedComboSeries

StackedComboSplineSeries

StackedImpl

StackedLineSeries

StackedMarkerSeries

StackedSplineSeries

StackingUtil

State

StyleSheet

Subscriber

SVGCircle

SVGDrawing

SVGEllipse

SVGGraphic

SVGPath

SVGPieSlice

SVGRect

SVGShape

SWF

SWFDetect

SyntheticEvent

SyntheticEvent.Notifier

SynthRegistry

Tab

TabView

Template

Template.Micro

Test.ArrayAssert

Test.Assert

Test.AssertionError

Test.ComparisonFailure

Test.Console

Test.CoverageFormat

Test.DateAssert

Test.EventTarget

Test.Mock

Test.Mock.Value

Test.ObjectAssert

Test.Reporter

Test.Results

Test.Runner

Test.ShouldError

Test.ShouldFail

Test.TestCase

Test.TestFormat

Test.TestNode

Test.TestRunner

Test.TestSuite

Test.UnexpectedError

Test.UnexpectedValue

Test.Wait

Text.AccentFold

Text.WordBreak

TimeAxis

TimeAxisBase

TimeImpl

ToggleButton

TopAxisLayout

Transition

Tree

Tree.Labelable

Tree.Node

Tree.Node.Labelable

Tree.Node.Openable

Tree.Node.Selectable

Tree.Node.Sortable

Tree.Openable

Tree.Selectable

Tree.Sortable

UA

Uploader

Uploader.Queue

UploaderFlash

UploaderHTML5

ValueChange

VerticalLegendLayout

View

View.NodeMap

VMLCircle

VMLDrawing

VMLEllipse

VMLGraphic

VMLPath

VMLPieSlice

VMLRect

VMLShape

Widget

WidgetAutohide

WidgetButtons

WidgetChild

WidgetModality

WidgetParent

WidgetPosition

WidgetPositionAlign

WidgetPositionConstrain

WidgetStack

WidgetStdMod

XML

YQL

YQLRequest

YUI

YUI~substitute

align-plugin

anim

anim-base

anim-color

anim-curve

anim-easing

anim-node-plugin

anim-scroll

anim-shape

anim-shape-transform

anim-xy

app

app-base

app-content

app-transitions

app-transitions-native

array-extras

array-invoke

arraylist

arraylist-add

arraylist-filter

arraysort

async-queue

attribute

attribute-base

attribute-complex

attribute-core

attribute-extras

attribute-observable

autocomplete

autocomplete-base

autocomplete-filters

autocomplete-filters-accentfold

autocomplete-highlighters

autocomplete-highlighters-accentfold

autocomplete-list

autocomplete-list-keys

autocomplete-plugin

autocomplete-sources

axis

axis-base

axis-category

axis-category-base

axis-numeric

axis-numeric-base

axis-stacked

axis-stacked-base

axis-time

axis-time-base

base

base-base

base-build

base-core

base-observable

base-pluginhost

button

button-core

button-group

button-plugin

cache

cache-base

cache-offline

cache-plugin

calendar

calendar-base

calendarnavigator

charts

charts-base

charts-legend

classnamemanager

clickable-rail

collection

color

color-base

color-harmony

color-hsl

color-hsv

console

console-filters

content-editable

cookie

createlink-base

dataschema

dataschema-array

dataschema-base

dataschema-json

dataschema-text

dataschema-xml

datasource

datasource-arrayschema

datasource-cache

datasource-function

datasource-get

datasource-io

datasource-jsonschema

datasource-local

datasource-polling

datasource-textschema

datasource-xmlschema

datatable

datatable-base

datatable-body

datatable-column-widths

datatable-core

datatable-datasource

datatable-foot

datatable-formatters

datatable-head

datatable-highlight

datatable-keynav

datatable-message

datatable-mutable

datatable-paginator

datatable-scroll

datatable-sort

datatable-table

datatype

datatype-date

datatype-date-format

datatype-date-math

datatype-date-parse

datatype-number

datatype-number-format

datatype-number-parse

datatype-xml

datatype-xml-format

datatype-xml-parse

dd

dd-constrain

dd-ddm

dd-ddm-base

dd-ddm-drop

dd-delegate

dd-drag

dd-drop

dd-drop-plugin

dd-gestures

dd-plugin

dd-proxy

dd-scroll

dial

dom

dom-base

dom-screen

dom-style

dump

editor

editor-base

editor-bidi

editor-br

editor-inline

editor-lists

editor-para

editor-para-base

editor-para-ie

editor-tab

escape

event

event-base

event-contextmenu

event-custom

event-custom-base

event-custom-complex

event-delegate

event-flick

event-focus

event-gestures

event-hover

event-key

event-mouseenter

event-mousewheel

event-move

event-outside

event-resize

event-simulate

event-synthetic

event-tap

event-touch

event-valuechange

exec-command

features

file

file-flash

file-html5

frame

gesture-simulate

get

get-nodejs

graphics

graphics-group

handlebars

handlebars-base

handlebars-compiler

highlight

highlight-accentfold

highlight-base

history

history-base

history-hash

history-hash-ie

history-html5

imageloader

intl

io

io-base

io-form

io-nodejs

io-queue

io-upload-iframe

io-xdr

json

json-parse

json-stringify

jsonp

jsonp-url

lazy-model-list

loader

loader-base

loader-yui3

matrix

model

model-list

model-sync-rest

node

node-base

node-core

node-data

node-event-delegate

node-event-html5

node-event-simulate

node-flick

node-focusmanager

node-load

node-menunav

node-pluginhost

node-screen

node-scroll-info

node-style

oop

overlay

paginator

paginator-core

paginator-url

panel

parallel

pjax

pjax-base

pjax-content

pjax-plugin

plugin

pluginhost

pluginhost-base

pluginhost-config

promise

querystring

querystring-parse

querystring-parse-simple

querystring-stringify

querystring-stringify-simple

queue-promote

range-slider

recordset

recordset-base

recordset-filter

recordset-indexer

recordset-sort

resize

resize-contrain

resize-plugin

resize-proxy

rollup

router

scrollview

scrollview-base

scrollview-base-ie

scrollview-list

scrollview-paginator

scrollview-scrollbars

selection

selector-css2

selector-css3

selector-native

series-area

series-area-stacked

series-areaspline

series-areaspline-stacked

series-bar

series-bar-stacked

series-base

series-candlestick

series-cartesian

series-column

series-column-stacked

series-combo

series-combo-stacked

series-combospline

series-combospline-stacked

series-curve-util

series-fill-util

series-histogram

series-line

series-line-stacked

series-line-util

series-marker

series-marker-stacked

series-ohlc

series-pie

series-plot-util

series-range

series-spline

series-spline-stacked

series-stacked

shim-plugin

slider

slider-base

slider-value-range

sortable

sortable-scroll

stylesheet

substitute

swf

swfdetect

tabview

template

template-base

template-micro

test

test-console

text

text-accentfold

text-wordbreak

timers

transition

transition-timer

tree

tree-labelable

tree-lazy

tree-node

tree-openable

tree-selectable

tree-sortable

uploader

uploader-flash

uploader-html5

uploader-queue

view

view-node-map

widget

widget-anim

widget-autohide

widget-base

widget-base-ie

widget-buttons

widget-child

widget-htmlparser

widget-modality

widget-parent

widget-position

widget-position-align

widget-position-constrain

widget-skin

widget-stack

widget-stdmod

widget-uievents

yql

yql-jsonp

yql-nodejs

yql-winjs

yui

yui-base

yui-later

yui-log

yui-throttle

        Show:

            <input type="checkbox" id="api-show-inherited" checked>
            Inherited

            <input type="checkbox" id="api-show-protected">
            Protected

            <input type="checkbox" id="api-show-private">
            Private

            <input type="checkbox" id="api-show-deprecated">
            Deprecated

File: date/js/date-format.js

/**
 * The `datatype` module is an alias for three utilities, Y.Date,
 * Y.Number and Y.XML, that provide type-conversion and string-formatting
 * convenience methods for various JavaScript object types.
 *
 * @module datatype
 * @main datatype
 */

/**
 * The Date Utility provides type-conversion and string-formatting
 * convenience methods for Dates.
 *
 * @module datatype-date
 * @main datatype-date
 */

/**
 * Date module.
 *
 * @module datatype-date
 */

/**
 * Format date module implements strftime formatters for javascript based on the
 * Open Group specification defined at
 * http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html
 * This implementation does not include modified conversion specifiers (i.e., Ex and Ox)
 *
 * @module datatype-date
 * @submodule datatype-date-format
 */

/**
 * Date provides a set of utility functions to operate against Date objects.
 *
 * @class Date
 * @static
 */

/**
 * Pad a number with leading spaces, zeroes or something else
 * @method xPad
 * @param x {Number}    The number to be padded
 * @param pad {String}  The character to pad the number with
 * @param r {Number}    (optional) The base of the pad, eg, 10 implies to two digits, 100 implies to 3 digits.
 * @private
 */
var xPad=function (x, pad, r)
{
    if(typeof r === "undefined")
    {
        r=10;
    }
    pad = pad + "";
    for( ; parseInt(x, 10)<r && r>1; r/=10) {
        x = pad + x;
    }
    return x.toString();
};

var Dt = {
    formats: {
        a: function (d, l) { return l.a[d.getDay()]; },
        A: function (d, l) { return l.A[d.getDay()]; },
        b: function (d, l) { return l.b[d.getMonth()]; },
        B: function (d, l) { return l.B[d.getMonth()]; },
        C: function (d) { return xPad(parseInt(d.getFullYear()/100, 10), 0); },
        d: ["getDate", "0"],
        e: ["getDate", " "],
        g: function (d) { return xPad(parseInt(Dt.formats.G(d)%100, 10), 0); },
        G: function (d) {
                var y = d.getFullYear();
                var V = parseInt(Dt.formats.V(d), 10);
                var W = parseInt(Dt.formats.W(d), 10);

                if(W > V) {
                    y++;
                } else if(W===0 && V>=52) {
                    y--;
                }

                return y;
            },
        H: ["getHours", "0"],
        I: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, 0); },
        j: function (d) {
                var gmd_1 = new Date("" + d.getFullYear() + "/1/1 GMT");
                var gmdate = new Date("" + d.getFullYear() + "/" + (d.getMonth()+1) + "/" + d.getDate() + " GMT");
                var ms = gmdate - gmd_1;
                var doy = parseInt(ms/60000/60/24, 10)+1;
                return xPad(doy, 0, 100);
            },
        k: ["getHours", " "],
        l: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, " "); },
        m: function (d) { return xPad(d.getMonth()+1, 0); },
        M: ["getMinutes", "0"],
        p: function (d, l) { return l.p[d.getHours() >= 12 ? 1 : 0 ]; },
        P: function (d, l) { return l.P[d.getHours() >= 12 ? 1 : 0 ]; },
        s: function (d, l) { return parseInt(d.getTime()/1000, 10); },
        S: ["getSeconds", "0"],
        u: function (d) { var dow = d.getDay(); return dow===0?7:dow; },
        U: function (d) {
                var doy = parseInt(Dt.formats.j(d), 10);
                var rdow = 6-d.getDay();
                var woy = parseInt((doy+rdow)/7, 10);
                return xPad(woy, 0);
            },
        V: function (d) {
                var woy = parseInt(Dt.formats.W(d), 10);
                var dow1_1 = (new Date("" + d.getFullYear() + "/1/1")).getDay();
                // First week is 01 and not 00 as in the case of %U and %W,
                // so we add 1 to the final result except if day 1 of the year
                // is a Monday (then %W returns 01).
                // We also need to subtract 1 if the day 1 of the year is
                // Friday-Sunday, so the resulting equation becomes:
                var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1);
                if(idow === 53 && (new Date("" + d.getFullYear() + "/12/31")).getDay() < 4)
                {
                    idow = 1;
                }
                else if(idow === 0)
                {
                    idow = Dt.formats.V(new Date("" + (d.getFullYear()-1) + "/12/31"));
                }

                return xPad(idow, 0);
            },
        w: "getDay",
        W: function (d) {
                var doy = parseInt(Dt.formats.j(d), 10);
                var rdow = 7-Dt.formats.u(d);
                var woy = parseInt((doy+rdow)/7, 10);
                return xPad(woy, 0, 10);
            },
        y: function (d) { return xPad(d.getFullYear()%100, 0); },
        Y: "getFullYear",
        z: function (d) {
                var o = d.getTimezoneOffset();
                var H = xPad(parseInt(Math.abs(o/60), 10), 0);
                var M = xPad(Math.abs(o%60), 0);
                return (o>0?"-":"+") + H + M;
            },
        Z: function (d) {
            var tz = d.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/, "$2").replace(/[a-z ]/g, "");
            if(tz.length > 4) {
                tz = Dt.formats.z(d);
            }
            return tz;
        },
        "%": function (d) { return "%"; }
    },

    aggregates: {
        c: "locale",
        D: "%m/%d/%y",
        F: "%Y-%m-%d",
        h: "%b",
        n: "\n",
        r: "%I:%M:%S %p",
        R: "%H:%M",
        t: "\t",
        T: "%H:%M:%S",
        x: "locale",
        X: "locale"
        //"+": "%a %b %e %T %Z %Y"
    },

     /**
     * Takes a native JavaScript Date and formats it as a string for display to user.
     *
     * @for Date
     * @method format
     * @param oDate {Date} Date.
     * @param oConfig {Object} (Optional) Object literal of configuration values:
     *  <dl>
     *   <dt>format {HTML} (Optional)</dt>
     *   <dd>
     *   <p>
     *   Any strftime string is supported, such as "%I:%M:%S %p". strftime has several format specifiers defined by the Open group at
     *   <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html">http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html</a>
     *   PHP added a few of its own, defined at <a href="http://www.php.net/strftime">http://www.php.net/strftime</a>
     *   </p>
     *   <p>
     *   This javascript implementation supports all the PHP specifiers and a few more.  The full list is below.
     *   </p>
     *   <p>
     *   If not specified, it defaults to the ISO 8601 standard date format: %Y-%m-%d.
     *   </p>
     *   <dl>
     *  <dt>%a</dt> <dd>abbreviated weekday name according to the current locale</dd>
     *  <dt>%A</dt> <dd>full weekday name according to the current locale</dd>
     *  <dt>%b</dt> <dd>abbreviated month name according to the current locale</dd>
     *  <dt>%B</dt> <dd>full month name according to the current locale</dd>
     *  <dt>%c</dt> <dd>preferred date and time representation for the current locale</dd>
     *  <dt>%C</dt> <dd>century number (the year divided by 100 and truncated to an integer, range 00 to 99)</dd>
     *  <dt>%d</dt> <dd>day of the month as a decimal number (range 01 to 31)</dd>
     *  <dt>%D</dt> <dd>same as %m/%d/%y</dd>
     *  <dt>%e</dt> <dd>day of the month as a decimal number, a single digit is preceded by a space (range " 1" to "31")</dd>
     *  <dt>%F</dt> <dd>same as %Y-%m-%d (ISO 8601 date format)</dd>
     *  <dt>%g</dt> <dd>like %G, but without the century</dd>
     *  <dt>%G</dt> <dd>The 4-digit year corresponding to the ISO week number</dd>
     *  <dt>%h</dt> <dd>same as %b</dd>
     *  <dt>%H</dt> <dd>hour as a decimal number using a 24-hour clock (range 00 to 23)</dd>
     *  <dt>%I</dt> <dd>hour as a decimal number using a 12-hour clock (range 01 to 12)</dd>
     *  <dt>%j</dt> <dd>day of the year as a decimal number (range 001 to 366)</dd>
     *  <dt>%k</dt> <dd>hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)</dd>
     *  <dt>%l</dt> <dd>hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.) </dd>
     *  <dt>%m</dt> <dd>month as a decimal number (range 01 to 12)</dd>
     *  <dt>%M</dt> <dd>minute as a decimal number</dd>
     *  <dt>%n</dt> <dd>newline character</dd>
     *  <dt>%p</dt> <dd>either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale</dd>
     *  <dt>%P</dt> <dd>like %p, but lower case</dd>
     *  <dt>%r</dt> <dd>time in a.m. and p.m. notation equal to %I:%M:%S %p</dd>
     *  <dt>%R</dt> <dd>time in 24 hour notation equal to %H:%M</dd>
     *  <dt>%s</dt> <dd>number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC</dd>
     *  <dt>%S</dt> <dd>second as a decimal number</dd>
     *  <dt>%t</dt> <dd>tab character</dd>
     *  <dt>%T</dt> <dd>current time, equal to %H:%M:%S</dd>
     *  <dt>%u</dt> <dd>weekday as a decimal number [1,7], with 1 representing Monday</dd>
     *  <dt>%U</dt> <dd>week number of the current year as a decimal number, starting with the
     *          first Sunday as the first day of the first week</dd>
     *  <dt>%V</dt> <dd>The ISO 8601:1988 week number of the current year as a decimal number,
     *          range 01 to 53, where week 1 is the first week that has at least 4 days
     *          in the current year, and with Monday as the first day of the week.</dd>
     *  <dt>%w</dt> <dd>day of the week as a decimal, Sunday being 0</dd>
     *  <dt>%W</dt> <dd>week number of the current year as a decimal number, starting with the
     *          first Monday as the first day of the first week</dd>
     *  <dt>%x</dt> <dd>preferred date representation for the current locale without the time</dd>
     *  <dt>%X</dt> <dd>preferred time representation for the current locale without the date</dd>
     *  <dt>%y</dt> <dd>year as a decimal number without a century (range 00 to 99)</dd>
     *  <dt>%Y</dt> <dd>year as a decimal number including the century</dd>
     *  <dt>%z</dt> <dd>numerical time zone representation</dd>
     *  <dt>%Z</dt> <dd>time zone name or abbreviation</dd>
     *  <dt>%%</dt> <dd>a literal "%" character</dd>
     *   </dl>
     *  </dd>
     * </dl>
     * @return {HTML} Formatted date for display.
     */
    format : function (oDate, oConfig) {
        oConfig = oConfig || {};

        if(!Y.Lang.isDate(oDate)) {
            Y.log("format called without a date", "WARN", "date");
            return Y.Lang.isValue(oDate) ? oDate : "";
        }

        var format, resources, compatMode, sLocale, LOCALE;

        format = oConfig.format || "%Y-%m-%d";

        resources = Y.Intl.get('datatype-date-format');

        var replace_aggs = function (m0, m1) {
            if (compatMode && m1 === "r") {
                return resources[m1];
            }
            var f = Dt.aggregates[m1];
            return (f === "locale" ? resources[m1] : f);
        };

        var replace_formats = function (m0, m1) {
            var f = Dt.formats[m1];
            switch(Y.Lang.type(f)) {
                case "string":                  // string => built in date function
                    return oDate[f]();
                case "function":                // function => our own function
                    return f.call(oDate, oDate, resources);
                case "array":                   // built in function with padding
                    if(Y.Lang.type(f[0]) === "string") {
                        return xPad(oDate[f[0]](), f[1]);
                    } // no break; (fall through to default:)
                default:
                    Y.log("unrecognised replacement type, please file a bug (format: " + oConfig.format + ")", "WARN", "date");
                    return m1;
            }
        };

        // First replace aggregates (run in a loop because an agg may be made up of other aggs)
        while(format.match(/%[cDFhnrRtTxX]/)) {
            format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs);
        }

        // Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a)
        var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats);

        replace_aggs = replace_formats = undefined;

        return str;
    }
};

Y.mix(Y.namespace("Date"), Dt);

Y.namespace("DataType");
Y.DataType.Date = Y.Date;


text:
from __future__ import print_function
import os
import numpy
import tarfile
import math
import sys
# for sphinx documentation, there seems to be trouble with importing shapely
# so for the time being, if we can't import it, since it doesn't actually matter
# for documentation, just have all the imported things wind up being undefined
try:
    import shapely.geometry as geometry
except OSError:
    pass
import helper_functions
import numpy as np
from helper_functions import warning

__author__ = 'greg'

class CsvOut:
    def __init__(self,project):
        # assert isinstance(project,aggregation_api.AggregationAPI)
        self.project = project

        self.project_id = project.project_id
        self.instructions = project.instructions
        self.workflow_names = project.workflow_names
        self.workflows = project.workflows

        print("workflows are " + str(self.workflows))

        self.__yield_aggregations__ = project.__yield_aggregations__
        self.retirement_thresholds = project.retirement_thresholds
        self.versions = project.versions

        self.__count_subjects_classified__ = project.__count_subjects_classified__

        # stores the file names
        self.file_names = {}
        self.workflow_directories = {}

    def __detailed_row__(self,workflow_id,task_id,subject_id,aggregations,followup_id=None,tool_id=None,cluster_index=None):
        """
        given the results for a given workflow/task and subject_id (and possibly shape and follow up id for marking)
        give a detailed results with the probabilities for each class
        """
        # key for accessing the csv output file
        id_ = (task_id,tool_id,followup_id,"detailed")

        # get what percentage of users voted for each classification
        votes,num_users = aggregations[task_id]

        # if a follow up question - the answers did is in a different format
        if followup_id is not None:
            answers_dict = self.instructions[workflow_id][task_id]["tools"][tool_id]["followup_questions"][followup_id]["answers"]
        else:
            # extract the text corresponding to each answer
            answers_dict = self.instructions[workflow_id][task_id]["answers"]

        with open(self.file_names[id_],"a") as csv_file:
            csv_file.write(str(subject_id))

            if cluster_index is not None:
                csv_file.write("," + str(cluster_index))

            # pretty sure that the answers should already be sorted by numerical key value
            # but if someone has been messing around with their tasks that might not be the case
            # so play it safe - extract the answer ids and sort them
            for answer_key in sorted(answers_dict.keys()):
                # todo - double check why the keys in "votes" are strings but in answer_key they are integers
                # not the end of the world, but worth double checking
                # if no one chose this particular answer, the probability was 0
                if str(answer_key) not in votes:
                    percentage = 0
                else:
                    percentage = votes[str(answer_key)]

                csv_file.write(","+str(percentage))

            csv_file.write(","+str(num_users)+"\n")

    def __marking_followup_rows__(self,workflow_id,task_id,subject_id,aggregations):
        """
        for a given task id /subject id, handle all of the marking/cluster related outputs for follow up questions
        I had thought about this function returning the rows to add to the csv (inside of the writing happening inside
        this function) - we wouldn't needed task_id or subject_id. But this function actually writes up to multiple
        csv files (for different follow up questions) and can have an arbitrary number of rows produced
        so it seems easiest if everything happens inside the function
        :param task_id: the id of the task - used to access the relevant csv output file
        :param subject_id: used to write out to the csv file so we know what subjects each line refers to
        :param followup_questions: the list of follow up questions for every marking tool associated with this task
        :return:
        """
        # get the marking_tasks
        tasks = self.workflows[workflow_id]
        # go through each tool

        all_shapes = set(tasks['marking'][task_id])

        # go through each shape separately
        for shape in all_shapes:
            # go through all clusters of this particular shape
            relevant_aggregations=aggregations[task_id][shape + " clusters"]
            for cluster_index,cluster in relevant_aggregations.items():
                # misc. info that should be skipped
                if cluster_index == "all_users":
                    continue

                # get the tool id for this cluster (which is the most likely tool to have created this cluster)
                try:
                    tool_id = cluster["most_likely_tool"]
                except KeyError:
                    print("skipping cluster")
                    continue
                # and the follow up questions
                # first check if there are any follow questions
                if "followup_questions" not in self.instructions[workflow_id][task_id]["tools"][tool_id]:
                    continue

                followup_questions = self.instructions[workflow_id][task_id]["tools"][tool_id]["followup_questions"]

                # go through each of the follow up questions
                for followup_index in followup_questions.keys():
                    # bit of a sanity check but we may have cases where the followup questions were not done
                    if "followup_question" not in relevant_aggregations[cluster_index]:
                        continue

                    # extract the responses to this specific followup question
                    try:
                        followup_aggregations = relevant_aggregations[cluster_index]["followup_question"][str(followup_index)]
                    except KeyError:
                        raise

                    # add both detailed and summary results for this particular follow up question
                    self.__detailed_row__(workflow_id,task_id,subject_id,{task_id:followup_aggregations[:]},followup_index,tool_id,cluster_index)
                    # and repeat with summary row

                    self.__classification_summary_row__(workflow_id,task_id,subject_id,{task_id:followup_aggregations[:]},followup_index,tool_id,cluster_index)

    def __marking_summary_row__(self,workflow_id,task_id,subject_id,aggregations,given_shape):
        """
        for a given shape, print out a summary of the all corresponding clusters  - one line more subject
        each line contains a count of the the number of such clusters which at least half the people marked
        the mean and median % of people to mark each cluster and the mean and median vote % for the
        most likely tool for each cluster. These last 4 values will help determine which subjects are "hard"
        :param workflow_id:
        :param task_id:
        :param subject_id:
        :param aggregations:
        :param shape:
        :return:
        """
        relevant_tools = [
            tool_id for tool_id, tool_shape
            in enumerate(self.workflows[workflow_id]['marking'][task_id])
            if tool_shape == given_shape
        ]
        counter = {t:{} for t in relevant_tools}
        aggreement = []

        prob_true_positive = []#{t:[] for t in relevant_tools}

        # go through every cluster with this associated shape
        for cluster_index,cluster in aggregations[task_id][given_shape + " clusters"].items():
            if cluster_index == "all_users":
                continue

            # how much agreement was their on the most likely tool?
            try:
                tool_prob = cluster["percentage"]
            except KeyError:
                continue

            aggreement.append(tool_prob)

            prob_true_positive.append(cluster["existence"][0]["1"])

            # count how many people used each marking tool int his cluster
            for u,t in zip(cluster["users"],cluster["tools"]):
                if u in counter[t]:
                    counter[t][u] += 1
                else:
                    counter[t][u] = 1

        # start off with the subject id
        row = str(subject_id) + ","
        # then add how often, on average, each tool marking was used
        for tool_id in sorted(counter.keys()):
            tool_count = counter[tool_id].values()
            if tool_count == []:
                row += "0,"
            else:
                row += str(numpy.median(tool_count)) + ","

        # if prob_true_positive == [] there were no clusters in the image
        # each the image was blank and there were no clusters at all - or none of them met the threshold of
        # 3 users per cluster
        # todo - might drop that 3 markings cluster threshold and report everything - let the researchers decide
        if prob_true_positive == []:
            row += "NA,NA,"
        else:
            row += str(numpy.mean(prob_true_positive)) + "," + str(numpy.median(prob_true_positive)) + ","

        # report how often people were in agreement about the tools used for each cluster
        # again, if there were no clusters at all - just report NA
        if aggreement == []:
            row += "NA,NA"
        else:

            row += str(numpy.mean(aggreement)) + "," + str(numpy.median(aggreement))

        id_ = task_id,given_shape,"summary"
        with open(self.file_names[id_],"a") as csv_file:
            csv_file.write(row + "\n")

    def __add_polygon_summary_row__(self,workflow_id,task_id,subject_id,aggregations):
        """
        print out a csv summary of the polygon aggregations (so not the individual xy points)
        need to know the workflow and task id so we can look up the instructions
        that way we can know if there is no output for a given tool - that tool wouldn't appear
        at all in the aggregations
        """
        polygon_tools = [t_index for t_index,t in enumerate(self.workflows[workflow_id][1][task_id]) if t == "polygon"]

        total_area = {t:0 for t in polygon_tools}

        id_ = task_id,"polygon","summary"
        for p_index,cluster in aggregations["polygon clusters"].items():
            if p_index == "all_users":
                continue

            tool_classification = cluster["tool_classification"][0].items()
            most_likely_tool,tool_probability = max(tool_classification, key = lambda x:x[1])
            total_area[int(most_likely_tool)] += cluster["area"]

        row = str(subject_id)
        for t in sorted([int(t) for t in polygon_tools]):
            row += ","+ str(total_area[t])

        with open(self.file_names[id_],"a") as csv_file:
            csv_file.write(row + "\n")

    def __classification_summary_row__(self,workflow_id,task_id,subject_id,aggregations,followup_id=None,tool_id = None,cluster_index=None):
        """
        given a result for a specific subject (and possibily a specific cluster within that specific subject)
        add one row of results to the summary file. that row contains
        subject_id,tool_index,cluster_index,most_likely,p(most_likely),shannon_entropy,mean_agreement,median_agreement,num_users
        tool_index & cluster_index are only there if we have a follow up to marking task
        :param id_:
        :param subject_id:
        :param results:
        :param answer_dict:
        :return:
        """
        # key for accessing the csv output in the dictionary
        id_ = (task_id,tool_id,followup_id,"summary")

        # get what percentage of users voted for each classification
        votes,num_users = aggregations[task_id]

        try:
            most_likely,top_probability = max(votes.items(), key = lambda x:x[1])

            # if tool_id is not None -> we have a follow up question
            # extract the text corresponding to the most likely answer
            # follow up questions for markings with have a different structure
            if tool_id is not None:
                answers = self.instructions[workflow_id][task_id]["tools"][tool_id]["followup_questions"][followup_id]["answers"]
                most_likely_label = answers[int(most_likely)]["label"]
            else:
                most_likely_label = self.instructions[workflow_id][task_id]["answers"][int(most_likely)]

            # and get rid of any bad characters
            most_likely_label = helper_functions.csv_string(most_likely_label)

            # calculate some summary values such as entropy and mean and median percentage of votes for each classification
            probabilities = votes.values()
            entropy = self.__shannon_entropy__(probabilities)

            mean_p = np.mean(votes.values())
            median_p = np.median(votes.values())

            with open(self.file_names[id_],"a") as results_file:
                results_file.write(str(subject_id)+",")

                if cluster_index is not None:
                    results_file.write(str(cluster_index)+",")

                # write out details regarding the top choice
                # this might not be a useful value if multiple choices are allowed - in which case just ignore it
                results_file.write(str(most_likely_label)+","+str(top_probability))
                # write out some summaries about the distributions of people's answers
                # again entropy probably only makes sense if only one answer is allowed
                # and mean_p and median_p probably only make sense if multiple answers are allowed
                # so people will need to pick and choose what they want
                results_file.write(","+str(entropy)+","+str(mean_p)+","+str(median_p))
                # finally - how many people have seen this subject for this task
                results_file.write(","+str(num_users)+"\n")
        # empty values should be ignored - but shouldn't happen too often either
        except ValueError:
            pass

    def __classification_file_setup__(self,output_directory,workflow_id):
        """
        create headers in the csv files - for both summary file and detailed results files for a given workflow/task
        :param output_directory:
        :param workflow_id:
        :param task_id:
        :param tool_id: if not None - then this is a follow up question to a marking task
        :param followup_id: if not None - then this is a follow up question to a marking task
        :return:
        """
        tasks = self.workflows[workflow_id]

        # go through the classification tasks - they will either be simple c. tasks (one answer allowed)
        # multiple c. tasks (more than one answer allowed) and possibly a follow up question to a marking
        for task_id in tasks['classification']:
            # is this task a simple classification task?
            # don't care if the questions allows for multiple answers, or requires a single one
            if tasks['classification'][task_id] in ["single","multiple"]:
                self.__detailed_classification_file_setup__(output_directory,workflow_id,task_id)
                self.__summary_classification_file_setup__(output_directory,workflow_id,task_id)

            else:
                # this classification task is actually a follow up to a marking task
                for tool_id in tasks['classification'][task_id]:
                    for followup_id,answer_type in enumerate(tasks['classification'][task_id][tool_id]):
                        self.__detailed_classification_file_setup__(output_directory,workflow_id,task_id,tool_id,followup_id)
                        self.__summary_classification_file_setup__(output_directory,workflow_id,task_id,tool_id,followup_id)

    def __detailed_classification_file_setup__(self,output_directory,workflow_id,task_id,tool_id=None,followup_id=None):
        """
        create a csv file for the detailed results of a classification task and set up the headers
        :param output_directory:
        :param workflow_id:
        :param task_id:
        :param tool_id:
        :param followup_id:
        :return:
        """
        # the file name will be based on the task label - which we need to make sure isn't too long and doesn't
        # have any characters which might cause trouble, such as spaces
        fname = self.__get_filename__(workflow_id,task_id,tool_id=tool_id,followup_id=followup_id)

        # start with the detailed results
        id_ = (task_id,tool_id,followup_id,"detailed")
        self.file_names[id_] = output_directory+fname

        # open the file and add the column headers
        with open(output_directory+fname,"wb") as detailed_results:
            # now write the headers
            detailed_results.write("subject_id")

            # the answer dictionary is structured differently for follow up questions markings
            if tool_id is not None:
                # if a follow up question - we will also add a column for the cluster id
                detailed_results.write(",cluster_id")

                answer_dict = dict()
                answers = self.instructions[workflow_id][task_id]["tools"]
                answers = answers[tool_id]["followup_questions"][followup_id]
                answers = answers.get("answers", {})

                for answer_key, answer in answers.items():
                    answer_dict[answer_key] = answer["label"]
            else:
                answer_dict = self.instructions[workflow_id][task_id]["answers"]

            # each possible response will have a separate column - this column will be the percentage of people
            # who selected a certain response. This works whether a single response or multiple ones are allowed
            for answer_key in sorted(answer_dict.keys()):
                # break this up into multiple lines so we can be sure that the answers are sorted correctly
                # order might not matter in the end, but just to be sure
                answer = answer_dict[answer_key]
                answer_string = helper_functions.csv_string(answer)[:50]
                detailed_results.write(",p("+answer_string+")")

            # the final column will give the number of user
            # for follow up question - num_users should be the number of users with markings in the cluster
            detailed_results.write(",num_users\n")

    def __detailed_marking_row__(self,workflow_id,task_id,subject_id,aggregations,shape):
        """
        output for line segments
        :param workflow_id:
        :param task_id:
        :param subject_id:
        :param aggregations:
        :return:
        """
        id_ = (task_id,shape,"detailed")

        for cluster_index,cluster in aggregations[shape + " clusters"].items():
            if cluster_index == "all_users":
                continue
            # convert to int - not really sure why but get stored as unicode
            cluster_index = int(cluster_index)

            # build up the row bit by bit to have the following structure
            # "subject_id,most_likely_tool,x,y,p(most_likely_tool),p(true_positive),num_users"
            row = str(subject_id)+","
            # todo for now - always give the cluster index
            row += str(cluster_index)+","

            # extract the most likely tool for this particular marking and convert it to
            # a string label
            # not completely sure why some clusters are missing this value but does seem to happen

            most_likely_tool = cluster["most_likely_tool"]
            # again - not sure why this percentage would be 0, but does seem to happen
            tool_probability = cluster["percentage"]
            assert tool_probability > 0

            # convert the tool into the string label
            tool_str = self.instructions[workflow_id][task_id]["tools"][int(most_likely_tool)]["marking tool"]
            row += helper_functions.csv_string(tool_str) + ","

            # get the central coordinates next
            for center_param in cluster["center"]:
                if isinstance(center_param,list) or isinstance(center_param,tuple):
                    # if we have a list, split it up into subpieces
                    for param in center_param:
                        row += str(param) + ","
                else:
                    row += str(center_param) + ","

            # add on how likely the most likely tool was
            row += str(tool_probability) + ","
            # how likely the cluster is to being a true positive and how many users (out of those who saw this
            # subject) actually marked it. For the most part p(true positive) is equal to the percentage
            # of people, so slightly redundant but allows for things like weighted voting and IBCC in the future
            prob_true_positive = cluster["existence"][0]["1"]
            num_users = cluster["existence"][1]
            row += str(prob_true_positive) + "," + str(num_users)

            with open(self.file_names[id_],"a") as csvfile:
                csvfile.write(row+"\n")

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        pass

    def __get_filename__(self,workflow_id,task_id,summary=False,tool_id=None,followup_id=None):
        """
        use the user's instructions to help create a file name to store the results in
        :param workflow_id:
        :param task_id:
        :param summary:
        :return:
        """
        assert (tool_id is None) or (followup_id is not None)

        # read in the instructions
        # if just a simple classification question
        if tool_id is None:
            instructions = self.instructions[workflow_id][task_id]["instruction"]
        # else a follow up question to a marking - so the instructions are stored in a sligghtly different spot
        else:
            instructions = (
                self.instructions[workflow_id][task_id]["tools"][tool_id]
                    ["followup_questions"][followup_id].get("question",  "")
            )

        fname = str(task_id) + instructions[:50]
        if summary:
            fname += "_summary"
        # get rid of any characters (like extra ","s) that could cause problems
        fname = helper_functions.csv_string(fname)
        fname += ".csv"

        return fname

    def __get_top_survey_followup__(self,votes,answers):
        """
        for a particular follow up classification question in a survey task where only one answer is allowed
        return the top/most likely classification and its associated probability
        :param aggregations:
        :return:
        """
        # list answer in decreasing order
        sorted_votes = sorted(votes.items(),key = lambda x:x[1],reverse=True)
        candidates,vote_counts = zip(*sorted_votes)

        top_candidate = candidates[0]
        percent = vote_counts[0]/float(sum(vote_counts))

        return answers[top_candidate]["label"],percent

    def __make_files__(self,workflow_id):
        """
        create all of the files necessary for this workflow
        :param workflow_id:
        :return:
        """
        # delete any reference to previous csv outputs - this means we don't have to worry about using
        # workflow ids in the keys and makes things simplier
        self.file_names = {}

        # now create a sub directory specific to the workflow
        try:
            workflow_name = self.workflow_names[workflow_id]
        except KeyError:
            warning(self.workflows)
            warning(self.workflow_names)
            raise

        # workflow names might have characters (such as spaces) which shouldn't be part of a filename, so clean up the
        # workflow names
        workflow_name = helper_functions.csv_string(workflow_name)
        output_directory = "/tmp/"+str(self.project_id)+"/" +str(workflow_id) + "_" + workflow_name + "/"

        if not os.path.exists(output_directory):
            os.makedirs(output_directory)
        self.workflow_directories[workflow_id] = output_directory

        # create the csv files for the classification tasks (both simple and follow up ones)
        self.__classification_file_setup__(output_directory,workflow_id)

        # now set things up for the marking tasks
        self.__marking_file_setup__(output_directory,workflow_id)

        self.__survey_file_setup__(output_directory,workflow_id)

        return output_directory

    def __marking_file_setup__(self,output_directory,workflow_id):
        """
        - create the csv output files for each workflow/task pairing where the task is a marking
        also write out the header line
        - since different tools (for the same task) can have completely different shapes, these shapes should
        be printed out to different files - hence the multiple output files
        - we will give both a summary file and a detailed report file
        """
        tasks = self.workflows[workflow_id]

        # iterate over each task and the shapes (not tools) available for each task
        for task_id,tools in tasks['marking'].items():
            for shape in set(tools):
                # get the file name - and remove any characters (such as spaces) which should not be in a file name
                fname = str(task_id) + self.instructions[workflow_id][task_id]["instruction"][:50]
                fname = helper_functions.csv_string(fname)

                # create the files - both detailed and summary
                self.file_names[(task_id,shape,"detailed")] = output_directory+"/"+fname + "_" + shape + ".csv"
                self.file_names[(task_id,shape,"summary")] = output_directory+"/"+fname + "_" + shape + "_summary.csv"

                # polygons - since they have an arbitary number of points are handled slightly differently
                if shape == "polygon":
                    self.__add_polygon_summary_row__()
                    self.__polygon_detailed_setup__(task_id)
                else:
                    # write the headers for the csv summary files
                    self.__marking_summary_header__(workflow_id,task_id,shape)
                    # and for the detailed
                    self.__marking_detailed_header__(task_id,shape)

    def __marking_detailed_header__(self,task_id,shape):
        """
        create the csv file headers for the detailed results
        :return:
        """
        assert shape != "polygon"

        id_ = task_id,shape,"detailed"
        with open(self.file_names[id_],"w") as csv_file:
            csv_file.write( "subject_id,cluster_index,most_likely_tool,")
            # the headers depend on the coordinates used to describe each shape
            if shape == "point":
                csv_file.write("x,y,")
            elif shape == "rectangle":
                # todo - fix this
                csv_file.write("x1,y1,x2,y2,")
            elif shape == "line":
                csv_file.write("x1,y1,x2,y2,")
            elif shape == "ellipse":
                csv_file.write("x1,y1,r1,r2,theta,")

            # how much agreement is there on the most likely tool and how likely this cluster is to be something real
            csv_file.write("p(most_likely_tool),p(true_positive),num_users\n")

    def __marking_summary_header__(self,workflow_id,task_id,shape):
        """
        setup the summary csv file for a given marking tool
        all shape aggregation will have a summary file - with one line per subject
        DON'T call this for polygons - they need to be handled differently
        :return:
        """
        assert shape != "polygon"

        id_ = task_id,shape,"summary"
        with open(self.file_names[id_],"w") as csv_file:
            # the summary file will contain just line per subject
            csv_file.write("subject_id")

            for tool_id, tool_shape in enumerate(
                self.workflows[workflow_id]['marking'][task_id]
            ):
                # does this particular tool use the desired shape?
                if tool_shape != shape:
                    continue

                # what is the label given to this tool - this is what we want to use in our column header
                # i.e. we don't want to say tool 0, or shape rectangle, we want to say "zebra"
                tool_label = self.instructions[workflow_id][task_id]["tools"][tool_id]["marking tool"]
                # remove any characters (such as spaces) which shouldn't be in a csv column header
                tool_label = helper_functions.csv_string(tool_label)

                csv_file.write(",median(" + tool_label +")")

            # as final stats to add
            csv_file.write(",mean_probability,median_probability,mean_tool,median_tool\n")

    def __polygon_detailed_setup__(self,task_id):
        """
        write out the headers for the detailed polygon output file
        slightly silly since its only one line but keeps things as in the same format as for other shapes
        :param workflow_id:
        :param task_id:
        :return:
        """
        id_ = task_id,"polygon","detailed"
        with open(self.file_names[id_],"w") as csv_file:
            csv_file.write("subject_id,cluster_index,most_likely_tool,area,list_of_xy_polygon_coordinates\n")

    def __polygon_row__(self,workflow_id,task_id,subject_id,aggregations):
        """
        print out results for a polygon - include the outline in pixels, the area (as a percentage of image area)
        and what is the most likely tool to have created this polygon
        :param workflow_id:
        :param task_id:
        :param subject_id:
        :param aggregations:
        :return:
        """
        id_ = task_id,"polygon","detailed"

        with open(self.file_names[id_],"a") as csv_file:
            for p_index,cluster in aggregations["polygon clusters"].items():
                if p_index == "all_users":
                    continue

                tool_classification = cluster["tool_classification"][0].items()
                most_likely_tool,tool_probability = max(tool_classification, key = lambda x:x[1])
                tool = self.instructions[workflow_id][task_id]["tools"][int(most_likely_tool)]["marking tool"]
                tool = helper_functions.csv_string(tool)

                row = str(subject_id) + ","+ str(p_index)+ ","+ tool + ","+ str(cluster["area"]) + ",\"" +str(cluster["center"]) + "\""

                csv_file.write(row+"\n")

    #
    #
    #
    # def __polygon_summary_setup__(self,workflow_id,task_id):
    #     """
    #     once the csv files have been created, write the headers
    #     :return:
    #     """
    #     id_ = task_id,"polygon","summary"
    #
    #     with open(self.file_names[id_],"w") as csv_file:
    #         # self.csv_files[id_].write("subject_id,\n")
    #         polygon_tools = [t_index for t_index,t in enumerate(self.workflows[workflow_id][1][task_id]) if t == "polygon"]
    #         csv_file.write("subject_id,")
    #         for tool_id in polygon_tools:
    #             tool = self.instructions[workflow_id][task_id]["tools"][tool_id]["marking tool"]
    #             tool = helper_functions.csv_string(tool)
    #             csv_file.write("area("+tool+"),")

    def __shannon_entropy__(self,probabilities):
        """
        calculate and return the shannon entropy
        :param probabilities:
        :return:
        """
        return -sum([p*math.log(p) for p in probabilities])

    def __subject_output__(self,subject_id,aggregations,workflow_id):
        """
        add csv rows for all the output related to this particular workflow/subject_id
        acts as a "dispatcher" for calling csv output for either classification tasks, marking tasks or survey tasks
        :param workflow_id:
        :param subject_id:
        :param aggregations:
        :return:
        """
        # get relevant information for this particular workflow
        tasks = self.workflows[workflow_id]
        instructions = self.instructions[workflow_id]

        # start with classification tasks
        for task_id in tasks['classification'].keys():
            # a subject might not have results for all tasks
            if task_id not in aggregations:
                continue

            # if this a marking task? - so we have follow up questions
            if task_id in tasks['marking']:
                # need the instructions for printing out labels
                followup_questions = tasks['classification'][task_id]
                self.__marking_followup_rows__(workflow_id,task_id,subject_id,aggregations)
            else:
                # we have a simple classification
                # start by output the summary
                self.__classification_summary_row__(workflow_id,task_id,subject_id,aggregations)
                self.__detailed_row__(workflow_id,task_id,subject_id,aggregations)

        for task_id,possible_shapes in tasks['marking'].items():
            for shape in set(possible_shapes):
                # not every task have been done for every aggregation
                if task_id in aggregations:
                    # polygons are different since they have an arbitrary number of points
                    if shape == "polygon":
                        self.__polygon_row__(workflow_id,task_id,subject_id,aggregations[task_id])
                        self.__add_polygon_summary_row__(workflow_id,task_id,subject_id,aggregations[task_id])
                    else:
                        self.__detailed_marking_row__(workflow_id,task_id,subject_id,aggregations[task_id],shape)
                        self.__marking_summary_row__(workflow_id,task_id,subject_id,aggregations,shape)

        for task_id in tasks['survey']:
            print(task_id)
            instructions = self.instructions[workflow_id][task_id]

            # id_ = (task_id,"summary")
            # with open(self.file_names[id_],"a") as f:
            #     summary_line = self.__survey_summary_row(aggregations)
            #     f.write(str(subject_id)+summary_line)
            # print(self.file_names.keys())
            id_ = task_id
            with open(self.file_names[id_],"a") as f:
                detailed_lines = self.__survey_row__(instructions,aggregations)
                for l in detailed_lines:
                    f.write(str(subject_id)+l)

    def __summary_classification_file_setup__(self,output_directory,workflow_id,task_id,tool_id=None,followup_id=None):
        """
        create the summary csv files and fill in the headers
        :param output_directory:
        :param workflow_id:
        :param task_id:
        :param tool_id:
        :param followup_id:
        :return:
        """
        fname = self.__get_filename__(workflow_id,task_id,summary = True,tool_id=tool_id,followup_id=followup_id)
        id_ = (task_id,tool_id,followup_id,"summary")
        self.file_names[id_] = output_directory+fname

        # add the columns
        with open(output_directory+fname,"wb") as summary_file:
            summary_file.write("subject_id,")

            # if a follow up question - we also provide cluster ids
            if tool_id is not None:
                summary_file.write("cluster_id,")

            summary_file.write("most_likely,p(most_likely),shannon_entropy,mean_agreement,median_agreement,num_users\n")

    def __survey_file_setup__(self,output_directory,workflow_id):
        """
        set up the csv files for surveys. we will just have one output file
        :param output_directory:
        :param workflow_id:
        :return:
        """
        tasks = self.workflows[workflow_id]

        for task_id in tasks['survey']:
            instructions = self.instructions[workflow_id][task_id]

            self.file_names[task_id] = output_directory+str(task_id) + ".csv"

            with open(self.file_names[task_id],"w") as csv_file:
                # now write the header
                header = "subject_id,num_classifications,pielou_score,species,"
                header += "percentage_of_votes_for_species,number_of_votes_for_species"

                # always include these headers for HWMN follow up question - these columns may be NA in output
                # but at least we have the header explaining why
                header += ",minimum_number_of_animals,most_likely_number_of_animals,percentage,maximum_number_of_animals"

                # todo - we'll assume, for now, that "how many" is always the first question
                # for followup_id in instructions["questionsOrder"]:
                for followup_id in instructions["questions"].keys():
                    multiple_answers = instructions["questions"][followup_id]["multiple"]
                    label = instructions["questions"][followup_id]["label"]

                    # the question "how many" is treated differently - we'll give the minimum, maximum and mostly likely
                    if followup_id == "HWMN":
                        continue
                    else:
                        if "behavior" in label:
                            stem = "behaviour:"
                        elif "behaviour" in label:
                            stem = "behaviour:"
                        else:
                            stem = helper_functions.csv_string(label)

                        if not multiple_answers:
                            header += ",most_likely(" + stem + ")"

                        for answer_id in instructions["questions"][followup_id]["answersOrder"]:
                            header += ",percentage(" + stem + helper_functions.csv_string(instructions["questions"][followup_id]["answers"][answer_id]["label"]) +")"

                csv_file.write(header+"\n")

    def __survey_how_many__(self,instructions,aggregations,species_id):
        """
        return the columns for the question how many animals are present in an image
        for survey tasks
        keep in mind that counts can be buckets - i.e. 10-19
        columns:
        min - the minimum number of animals anyone said
        most_likely - the bucket with the highest percentage
        percentage - how many people said the most likely
        max - the maximum number of animals anyone said
        :return:
        """

        followup_id = "HWMN"
        followup_question = instructions["questions"][followup_id]

        try:
            votes = aggregations[species_id]["followup"][followup_id].items()
        except KeyError:
            return ",NA,NA,NA,NA"
        # sort by num voters
        sorted_votes = sorted(votes,key = lambda x:x[1],reverse=True)
        candidates,vote_counts = zip(*sorted_votes)
        candidates = list(candidates)

        # top candidate is the most common response to the question of how many animals there are in the subject
        top_candidate = followup_question["answers"][candidates[0]]["label"]
        percentage = vote_counts[0]/float(sum(vote_counts))

        # what is the minimum/maximum number of animals of this species that people said were in the subject?
        answer_order = followup_question["answersOrder"]
        # resort by position in answer order
        candidates.sort(key = lambda x:answer_order.index(x))
        minimum_species = followup_question["answers"][candidates[0]]["label"]
        maximum_species = followup_question["answers"][candidates[-1]]["label"]

        return "," + str(minimum_species) + "," + str(top_candidate) + "," + str(percentage) + "," + str(maximum_species)

    def __survey_row__(self,instructions,aggregations):
        """
        for a given workflow, task and subject print one row of aggregations per species found to a csv file
        where the task correspond to a survey task
        :param workflow_id:
        :param task_id:
        :param subject_id:
        :param aggregations:
        :return:
        """
        # what we are returning (to be printed out to file elsewhere)
        rows = []

        # in dev - for a small project a few bad aggregations got into the system - so filer them out
        if max(aggregations["num species"]) == 0:
            return []

        # on average, how many species did people see?
        # note - nothing here (or empty or what ever) counts as a species - we just won't give any follow up
        # answer responses
        species_in_subject = aggregations.get("num species in image", [])

        views_of_subject = aggregations["num users"]

        pielou = aggregations["pielou index"]

        # only go through the top X species - where X is the median number of species seen
        for species_id,_ in species_in_subject:
            if species_id == "num users":
                continue

            # how many people voted for this species?
            num_votes = aggregations[species_id]["num votes"]
            percentage = num_votes/float(views_of_subject)

            # extract the species name - just to be sure, make sure that the label is "csv safe"
            species_label = helper_functions.csv_string(instructions["species"][species_id])
            row = "," + str(views_of_subject) + "," + str(pielou) + "," + species_label + "," + str(percentage) + "," + str(num_votes)

            # if there is nothing here - there are no follow up questions so just move on
            # same with FR - fire, NTHNG - nothing
            if species_id in ["NTHNGHR","NTHNG","FR"]:
                break

            # do the how many question first
            row += self.__survey_how_many__(instructions,aggregations,species_id)

            # now go through each of the other follow up questions
            # for followup_id in instructions["questionsOrder"]:
            for ii,followup_id in enumerate(instructions["questions"].keys()):
                followup_question = instructions["questions"][followup_id]

                if followup_question["label"] == "How many?":
                    # this gets dealt with separately
                    continue

                multiple_answers = instructions["questions"][followup_id]["multiple"]

                # this follow up question might not be relevant to the particular species
                if followup_id not in aggregations[species_id]["followup"]:
                    # if we do not allow for multiple answers, include blank columns for top candidate
                    # and corresponding percentage
                    if not multiple_answers:
                        row += ","

                    # add in a blank column for each follow up answer (since none of these answers are relevant)
                    for _ in instructions["questions"][followup_id]["answersOrder"]:
                        row += ","
                else:
                    votes = aggregations[species_id]["followup"][followup_id]

                    # if users are only allowed to pick a single answer - return the most likely answer
                    # but still give the individual break downs

                    if not multiple_answers:
                        votes = aggregations[species_id]["followup"][followup_id]
                        answers =(instructions["questions"][followup_id]["answers"])
                        top_candidate,percent = self.__get_top_survey_followup__(votes,answers)

                        row += "," + str(top_candidate)# + "," + str(percent)

                    for answer_id in instructions["questions"][followup_id]["answersOrder"]:

                        if answer_id in votes:
                            row += "," + str(votes[answer_id]/float(num_votes))
                        else:
                            row += ",0"

            # print(len(row.split(",")))
            # assert len(row.split(",")) == 58
            rows.append(row+"\n")

        return rows

    def __write_out__(self,subject_set = None):
        """
        create the csv outputs for a given set of workflows
        the workflows are specified by self.workflows which is determined when the aggregation engine starts
        a zipped file is created in the end
        """
        assert (subject_set is None) or isinstance(subject_set,set) or isinstance(subject_set,list)

        project_prefix = str(self.project_id)

        # create an output directory if it doesn't already exist
        if not os.path.exists("/tmp/"+str(self.project_id)):
            os.makedirs("/tmp/"+str(self.project_id))

        # go through each workflow independently
        for workflow_id in self.workflows:
            print("writing out workflow " + str(workflow_id))

            if self.__count_subjects_classified__(workflow_id) == 0:
                print("skipping due to no subjects being classified for the given workflow")
                continue

            # # create the output files for this workflow
            self.__make_files__(workflow_id)

            # results are going to be ordered by subject id (because that's how the results are stored)
            # so we can going to be cycling through task_ids. That's why we can't loop through classification_tasks etc.
            for subject_id,aggregations in self.__yield_aggregations__(workflow_id,subject_set):
                print(subject_id)
                self.__subject_output__(subject_id,aggregations,workflow_id)

        with open("/tmp/"+project_prefix+"/readme.txt", "w") as readme_file:
            readme_file.write("For documentation about the aggregation results please see https://github.com/zooniverse/aggregation/wiki/Understanding-Aggregation-Results")

        # compress the results directory
        tar_file_path = "/tmp/" + project_prefix + "_export.tar.gz"
        with tarfile.open(tar_file_path, "w:gz") as tar:
            tar.add("/tmp/"+project_prefix+"/",arcname=project_prefix)

        return tar_file_path

    # def __polygon_heatmap_output__(self,workflow_id,task_id,subject_id,aggregations):
    #     """
    #     print out regions according to how many users selected that user - so we can a heatmap
    #     of the results
    #     :param workflow_id:
    #     :param task_id:
    #     :param subject_id:
    #     :param aggregations:
    #     :return:
    #     """
    #     key = task_id+"polygon_heatmap"
    #     for cluster_index,cluster in aggregations["polygon clusters"].items():
    #         # each cluster refers to a specific tool type - so there can actually be multiple blobs
    #         # (or clusters) per cluster
    #         # not actually clusters
    #
    #         if cluster_index in ["param","all_users"]:
    #             continue
    #
    #         if cluster["tool classification"] is not None:
    #             # this result is not relevant to the heatmap
    #             continue
    #
    #         row = str(subject_id) + "," + str(cluster["num users"]) + ",\"" + str(cluster["center"]) + "\""
    #         self.csv_files[key].write(row+"\n")

if __name__ == "__main__":
    import aggregation_api
    project_id = sys.argv[1]
    project = aggregation_api.AggregationAPI(project_id,"development")

    w = CsvOut(project)
    w.__write_out__()

redpajama_set_name: RedPajamaGithub


text:
The *beamtools* package is a collection of methods to assist with several aspects of optical system design and analysis.

## Importing data
One of the most useful methods in the package is `import_data_file` which can be used to seamlessly import a variety of data types.

### Importing data with `beamtools.import_data_file()`
Once of the most useful methods in the package is `import_data_file` which can be used to seamlessly import a variety of data types.
```
import beamtools as bt

#data from an ocean optics spectrometer
file = 'testdata.csv'
type = 'oo_spec'

data = bt.import_data_file(file,type)
```
Data imported by `import_data_file` is returned as a DataObject. In this example, `data.wavelength` and `data.intensity` returns numpy arrays of the wavelength and intensity data imported from the file.
Any header information is stored in `data.header`. The header syntax for each file is defined in `file_formats.py`.

### Data Objects
All raw data in the package is handle via a DataObj where the data is stored as object attributes. Data objects are created from dictionaries (set of key/value pairs) and the Data Object attributes are defined by the dictionary keys. The class definition can be found in `.import_data_file.py`.
All `DataObj` instances posses the class method `fields()`. Calling `DataObj.fields()` returns a list of the onjects attributes. This can be used to view the names available data arrays.

### File formats
A list of file formats can be found in `file_formats.py`. I have already included many common file types. More can be added to the package in the future by creating additional dictionary entries following the format and keywords given. Each file format includes a key named `alias`. These values comprise a set of alternate names which can be used anywhere in the package when specifying a file type.

## Common methods

## `beamtools.pulse` module
The `beamtools.pulse` module contains many methods for analysing optical pulse. This includes the analysis of spectra and autocorrelation traces.

## `beamtools.upp` module
The ultrafast pulse propagation module, imported as `beamtools.ufpp` possess numerous methods pertaining to the numerical propogation of ultrafast pulses. This includes nonlinear fiber-optic equations, fiber amplification, and several simulated fiber-optic components.

## `beamtools.grating` module


text:
"""Pylons environment configuration"""
import os

from genshi.template import TemplateLoader
from pylons import config
from sqlalchemy import engine_from_config

import texcore.lib.app_globals as app_globals
import texcore.lib.helpers
from texcore.config.routing import make_map
from texcore.model import init_model

def load_environment(global_conf, app_conf):
    """Configure the Pylons environment via the ``pylons.config``
    object
    """
    # Pylons paths
    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    paths = dict(root=root,
                 controllers=os.path.join(root, 'controllers'),
                 static_files=os.path.join(root, 'public'),
                 templates=[os.path.join(root, 'templates')])

    # Initialize config with the basic options
    config.init_app(global_conf, app_conf, package='texcore', paths=paths)

    config['routes.map'] = make_map()
    config['pylons.app_globals'] = app_globals.Globals()
    config['pylons.h'] = texcore.lib.helpers

    # Create the Genshi TemplateLoader
    config['pylons.app_globals'].genshi_loader = TemplateLoader(
        paths['templates'], auto_reload=True)

    # Setup the SQLAlchemy database engine
    engine = engine_from_config(config, 'sqlalchemy.')
    init_model(engine)

    # CONFIGURATION OPTIONS HERE (note: all config options will override
    # any Pylons config options)


text:
package org.seqcode.viz.paintable.layout;

import java.awt.*;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Vector;

import javax.swing.Action;

import org.seqcode.viz.paintable.AbstractPaintable;
import org.seqcode.viz.paintable.Paintable;

public class StackedPaintable
extends AbstractPaintable {

    private boolean fVertical;
    private Vector<Paintable> fArray;

    public StackedPaintable() {
        super();
        fVertical = true;
        fArray = new Vector<Paintable>();
    }

    public StackedPaintable(Paintable... p) {
        super();
        fVertical = true;
        fArray = new Vector<Paintable>();
        for(int i = 0; i < p.length; i++) {
        	fArray.add(p[i]);
        	p[i].addPaintableChangedListener(this);
        }
    }

    public StackedPaintable(boolean vert, Paintable... p) {
        super();
        fVertical = vert;
        fArray = new Vector<Paintable>();
        for(int i = 0; i < p.length; i++) {
        	fArray.add(p[i]);
        	p[i].addPaintableChangedListener(this);
        }
    }

    public int size() { return fArray.size(); }
    public void addPaintable(Paintable p) {
        fArray.add(p);
        p.addPaintableChangedListener(this);
    }
    public boolean isVertical() { return fVertical; }

    public void toggleVertical() {
        fVertical = !fVertical;
        dispatchChangedEvent();
    }

    public void registerClick(double xf, double yf) {
        if(fArray.size() > 0) {
            double span = 1.0 / (double)fArray.size();
            if(fVertical) {
                int index = (int)Math.floor(yf * (double)fArray.size());
                fArray.get(index).registerClick(xf, (yf - (span * index)) / span);
            } else {
                int index = (int)Math.floor(xf * (double)fArray.size());
                fArray.get(index).registerClick((xf - (span * index)) / span, yf);
            }
        }
    }

    public Collection<Action> getPaintableActions() {
        LinkedList<Action> lst = new LinkedList<Action>();
        for(Paintable p : fArray) {
            lst.addAll(p.getPaintableActions());
        }
        return lst;
    }

    public void paintItem(Graphics g,
            int x1, int y1, int x2, int y2) {

        if(fArray.size() == 0) { return; }
        int stackedHeight =
            (int)Math.floor((double)(y2 - y1) / (double)fArray.size());
        int stackedWidth =
            (int)Math.floor((double)(x2 - x1) / (double)fArray.size());

        for(int i = 0; i < fArray.size(); i++) {
            Paintable p = fArray.get(i);

            if(fVertical) {
                p.paintItem(g, x1, y1 + (i * stackedHeight),
                        x2, y1 + ((i + 1) * stackedHeight));
            } else {
                p.paintItem(g, x1 + (i * stackedWidth), y1,
                        x1 + ((i + 1) * stackedWidth), y2);
            }
        }
    }
}


text:
id: 2573
title: Disabilitare l'aggiornamento automatico di WordPress
author: Stefano Marzorati
layout: post
guid: http://marzorati.co/?p=2573
permalink: /disabilitare-laggiornamento-automatico-di-wordpress/
authorsure_include_css:
  -
dsq_thread_id:
  - 2045523724
categories:
  - Linux
  - Windows
tags:
  - automatic
  - disable
  - update
  - wordpress
---
Basta aprire il file **wp-config.php** e aggiungere la seguente riga:

`define( 'WP_AUTO_UPDATE_CORE', false );`

Se si vuole disabilitare anche i temi e i plugins, la riga da aggiungere a **wp-config.php** è la seguente:

`define( 'AUTOMATIC_UPDATER_DISABLED', true );`

Maggiori dettagli li potete trovare qua


text:
package phonegap.pgmultiview;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.LOG;
import org.json.JSONException;

import static android.app.Activity.RESULT_OK;

public class PGMultiView extends CordovaPlugin {
    public CallbackContext callbackContext;
    protected static final String LOG_TAG = "PGMultiView";
    public static int RESULT_CODE =42;

// @param action the action to execute.
// @param args JSONArry of arguments for the plugin.
// @param the context used when calling back to JS .
// @return boolean success or fail

//Cordova is context of main activity.  webView is the webview we are running the main Activity (cordova) inside of.

    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);
    }

    public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
        this.callbackContext = callbackContext;

        if (action.equals("loadView")) {
            final String url = args.getString(0);
            final String message = args.getString(1);
            startCordovaActivity(url, message);
        } else if (action.equals("dismissView")) {
            final String message = args.getString(0);
            quit(message);
            //getMessage() is for the child activity (PGMultiViewActivity.java), not the parent
        } else if(action.equals("getMessage")) {
            PGMultiViewActivity act = (PGMultiViewActivity) this.cordova.getActivity();
            String message = act.getMessage();
            callbackContext.success(message);
        }
        return true;
    }

    //Launch child activity(PGMultiViewActivity.java), send start url and message in an intent
    private void startCordovaActivity(final String url, final String messageToChild) { //url is passed in from execute, its args.getstring(0)
        Intent intent = new Intent(this.cordova.getActivity(), PGMultiViewActivity.class);
        intent.putExtra("start URL", url);
        intent.putExtra("Message to child", messageToChild);
        cordova.startActivityForResult(this, intent, RESULT_CODE);
    }

    //when we get the result of the child activity back, create a bundle that we unpack the "message to parent" from
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        Bundle bundle = intent.getExtras();
        if (requestCode == RESULT_CODE) {
            if (resultCode == RESULT_OK) {
                String messageFromChild = bundle.getString("Message to parent");
                callbackContext.success(messageFromChild);
            }
        }
    }

    //required to make callbacks work with the plugin
    public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) {
        this.callbackContext = callbackContext;
    }

    //in the child activity when the user clicks the "navigate to parent button":
    private void quit(String message) {
        Intent result = new Intent();
        result.putExtra("Message to parent", message);
        this.cordova.getActivity().setResult(Activity.RESULT_OK, result);
        this.cordova.getActivity().finish();
    }
}


text:
id: 1381
title: Baby Log — another app for new parents
date: 2015-12-17T12:22:40+00:00
author: Junda Ong
layout: post
guid: http://blog.just2us.com/?p=1381
permalink: /2015/12/baby-log%e2%80%8a-%e2%80%8aanother-app-for-new-parents/
switch_like_status:
  - 1
sharing_disabled:
  - 1
dsq_thread_id:
  - 4411104631
categories:
  - Applications
tags:
  - Baby Log
---

_[Originally posted on Medium:](https://blog.jade2us.com/baby-log-another-app-for-new-parents-984696d02152#.5u5t1emw5)_

Shortly after launching [Jade](http://jade2us.com/), I started on a new app.

While Jade is a great journal app to pen down memorable moments with your child, logging mundane stuff — feedings, diaper change, weight, etc— is best logged somewhere else.

I use a note book and physically record these mundane stuff.

![](/img/babylog-notebook.jpeg)

On a typical day, I could record up to 8 feedings and 8 diaper change! That's a lot of times I have to flip open the book, and write down the time and details.

## Benefits of logging

I am not a believer of logging too much. I didn't want to log in a book at first..

But after a few loud shrieks that left me totally clueless on _WHY ARE YOU CRYING_, I decided it is best that we (all caregivers) know:

- when and how much was the baby last fed?
- when was the last diaper change?
- when and how long was the sleep?
- is there constipation?
- is baby gaining weight normally?

Turned out keeping a log book answer these questions.

And so I turned the log book into an app (:

![](/img/babylog-appicon.png)

## Download Baby Log

There are many similar apps that tracks the same thing. One of the most popular is [Baby Connect](https://itunes.apple.com/app/id326574411?mt=8) (formally Activity Logger), which cost US$4.99, but I find it complex to use.

![](/img/babyconnect-dashboard.png) Baby Connect's Dashboard
{:.caption}

Perhaps they are too comprehensive, had too many different data to show/add, therefore a glance at their Dashboard makes me dizzy..

And so I designed Baby Log to be elegant and fast to use.

![](/img/babylog-screenshots.png)

I also designed the Photo album to display Kate's photos with her age, so we can see her growing beautifully (:

Baby Log is a paid app, at US$1.99. Find out more from the [App Store](https://itunes.apple.com/app/id1065722243?at=11luru).

You can also use one of the [2O promo codes](http://codehookup.com/ffc8d7fe) to download for FREE, if you are lucky.

_Also, check out [Jade](http://jade2us.com/), a free app for parents to co-write a journal for their child._


text:
describe ContainerProjectHelper::TextualSummary do
  include_examples "textual_group", "Relationships", %i(
    ems
    container_routes
    container_services
    container_replicators
    container_groups
    container_nodes
    container_images
    container_templates
    custom_button_events
  )
  include_examples "textual_group", "Properties", %i(name display_name creation_timestamp resource_version)
  include_examples "textual_group_smart_management"
end


text:
package jp.co.mokha.shibboleth.idp.testing;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import edu.internet2.middleware.shibboleth.idp.authn.provider.AbstractLoginHandler;
import edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper;

public class TestingLoginHandler extends AbstractLoginHandler {

    /** Class logger. */
    private final Logger log = LoggerFactory.getLogger(TestingLoginHandler.class);

    /** The context-relative path of the servlet used to perform authentication. */
    private String authenticationServletPath;

    public TestingLoginHandler(String servletPath) {
        super();
        setSupportsPassive(false);
        setSupportsForceAuthentication(true);
        authenticationServletPath = servletPath;
    }

    public void login(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse) {
        // forward control to the servlet.
        try {
            final String authnServletUrl =
                    HttpServletHelper.getContextRelativeUrl(httpRequest, authenticationServletPath)
                    .buildURL();
            log.debug("Redirecting to {}", authnServletUrl);
            httpResponse.sendRedirect(authnServletUrl);
            return;
        } catch (IOException ex) {
            log.error("Unable to redirect to authentication servlet.", ex);
        }

    }
}


text:
/**
 *******************************************************************************
 * KVStoreAsyncAccess.h                                                        *
 *                                                                             *
 * Key value store accessor:                                                   *
 *   - Access to KV store                                                      *
 *******************************************************************************
 */

#ifndef _KV_STORE_ASYNC_ACCESSOR_H_
#define _KV_STORE_ASYNC_ACCESSOR_H_

/*
 *******************************************************************************
 *  Headers                                                                    *
 *******************************************************************************
 */
#include "stdinclude.h"

#include "KVStore.h"

#include <map>
#include <vector>
#include <string>

#include <boost/asio.hpp>

/*
 *******************************************************************************
 *  Forward declaraction                                                       *
 *******************************************************************************
 */

/*
 *******************************************************************************
 *  Class declaraction                                                         *
 *******************************************************************************
 */

class KVStoreAsyncAccessor {
public:
    KVStoreAsyncAccessor(boost::asio::io_service& io,
                         KVStore& store) :
        m_strand(io),
        m_store(store) {
    }
    virtual ~KVStoreAsyncAccessor() {
    }

    template<typename RD_HANDLER >
    void async_read(const std::string& key, int replica_type,
                    RD_HANDLER handler) {
        m_strand.post([=](){
                          std::vector<unsigned char> v;
                          int rc = m_store.do_read(key, replica_type, v);
                          handler(rc, v.data(), v.size());
                      });
    }

    template<typename WR_HANDLER >
    void async_write(const std::string& key, int replica_type,
                     const unsigned char* value, const size_t sz,
                     WR_HANDLER handler)
    {
        // TODO: memory pointed by value must be exist when handler called
        m_strand.post([=](){
                          std::vector<unsigned char> v;
                          v.resize(sz);
                          memcpy(v.data(), value, sz);
                          int rc = m_store.do_write(key, replica_type, v);
                          handler(rc);
                      });
    }

    template<typename UP_HANDLER >
    void async_update(const std::string& key, int replica_type,
                      const unsigned char* value, const size_t sz,
                      UP_HANDLER handler) {
        m_strand.post([=](){
                          std::vector<unsigned char> v;
                          v.resize(sz);
                          memcpy(v.data(), value, sz);
                          int rc = m_store.do_update(key, replica_type, v);
                          handler(rc);
                      });
    }

    template<typename DEL_HANDLER >
    void async_delete(const std::string& key, int replica_type,
                      DEL_HANDLER handler) {
        m_strand.post([=](){
                          int rc = m_store.do_delete(key, replica_type);
                          handler(rc);
                      });
    }

    template<typename GET_HANDLER >
    void async_get(int replica_type, bool remove, GET_HANDLER handler) {
        m_strand.post([=]() {
            std::map<std::string, std::vector<unsigned char> > v;
            int rc = m_store.do_get(replica_type, v, remove);
            handler(rc, v);
        });
    }

    template<typename DEL_HANDLER >
    void async_delete(int replica_type, DEL_HANDLER handler ) {
        m_strand.post([=]() {
            int rc = m_store.do_delete(replica_type);
            handler(rc);
        });
    }
private:
    boost::asio::io_service::strand m_strand;
    KVStore&                        m_store;
};

/*
 *******************************************************************************
 *  Inline functions                                                           *
 *******************************************************************************
 */

#endif // _KV_STORE_ASYNC_ACCESSOR_H_


text:
package com.rhc.mock.repositories;

import com.rhc.aggregates.Customer;
import com.rhc.repositories.api.CustomerStageRepository;

public class MockCustomerStageRepository extends AbstractMapCrudRepository<Customer> implements CustomerStageRepository {

}