text:
use device_types::{
    devices::{
        Dataset, Device, LogicalVolume, MdRaid, Mpath, Partition, Root, ScsiDevice, VolumeGroup,
        Zpool,
    },
    get_vdev_paths,
    mount::{FsType, Mount, MountPoint},
    DevicePath,
};
use iml_tracing::tracing;
use iml_wire_types::Fqdn;
use std::{
    cmp::Ordering,
    collections::{BTreeMap, BTreeSet, HashMap},
    fmt::Display,
    hash::{Hash, Hasher},
};

#[derive(Debug, Clone, Eq, serde::Serialize)]
pub struct MajorMinor(pub String);

impl Ord for MajorMinor {
    fn cmp(&self, other: &MajorMinor) -> Ordering {
        self.0.partial_cmp(&other.0).unwrap()
    }
}

impl PartialOrd for MajorMinor {
    fn partial_cmp(&self, other: &MajorMinor) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for MajorMinor {
    fn eq(&self, other: &MajorMinor) -> bool {
        self.0 == other.0
    }
}

impl Hash for MajorMinor {
    fn hash<H: Hasher>(&self, h: &mut H) {
        self.0.hash(h)
    }
}

impl<D1: Display, D2: Display> From<(D1, D2)> for MajorMinor {
    fn from((major, minor): (D1, D2)) -> MajorMinor {
        MajorMinor(format!("{}:{}", major, minor))
    }
}

#[derive(Debug, Clone, serde::Serialize)]
pub struct LinuxPluginMpathDevice<'a> {
    name: &'a str,
    block_device: MajorMinor,
    nodes: BTreeSet<LinuxPluginDevice<'a>>,
}

#[derive(Debug, Clone, serde::Serialize)]
pub struct LinuxPluginVgDevice<'a> {
    name: &'a str,
    uuid: &'a str,
    size: u64,
    pvs_major_minor: BTreeSet<MajorMinor>,
}

#[derive(Debug, Clone, serde::Serialize)]
pub struct LinuxPluginLvDevice<'a> {
    block_device: MajorMinor,
    size: u64,
    uuid: &'a str,
    name: &'a str,
}

#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize)]
pub struct LinuxPluginDevice<'a> {
    major_minor: MajorMinor,
    parent: Option<MajorMinor>,
    partition_number: Option<u64>,
    path: &'a DevicePath,
    paths: BTreeSet<&'a DevicePath>,
    serial_83: &'a Option<String>,
    serial_80: &'a Option<String>,
    size: Option<u64>,
    filesystem_type: &'a Option<String>,
}

#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize)]
pub struct LinuxPluginZpool<'a> {
    block_device: MajorMinor,
    drives: BTreeSet<MajorMinor>,
    name: &'a str,
    path: &'a str,
    size: u64,
    uuid: u64,
}

#[derive(Debug, Clone, serde::Serialize)]
#[serde(untagged)]
pub enum LinuxPluginItem<'a> {
    LinuxPluginDevice(LinuxPluginDevice<'a>),
    LinuxPluginZpool(LinuxPluginZpool<'a>),
}

impl<'a> Ord for LinuxPluginDevice<'a> {
    fn cmp(&self, other: &LinuxPluginDevice) -> Ordering {
        self.major_minor.partial_cmp(&other.major_minor).unwrap()
    }
}

impl<'a> PartialOrd for LinuxPluginDevice<'a> {
    fn partial_cmp(&self, other: &LinuxPluginDevice) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

#[derive(Debug, Clone, serde::Serialize)]
pub struct LinuxPluginData<'a> {
    pub devs: BTreeMap<MajorMinor, LinuxPluginItem<'a>>,
    pub local_fs: BTreeMap<MajorMinor, (&'a MountPoint, &'a FsType)>,
    pub mpath: BTreeMap<&'a str, LinuxPluginMpathDevice<'a>>,
    pub vgs: BTreeMap<&'a str, LinuxPluginVgDevice<'a>>,
    pub lvs: BTreeMap<&'a str, BTreeMap<&'a str, LinuxPluginLvDevice<'a>>>,
    pub zfspools: BTreeMap<u64, LinuxPluginZpool<'a>>,
    pub zfsdatasets: BTreeMap<u64, LinuxPluginZpool<'a>>,
}

impl<'a> Default for LinuxPluginData<'a> {
    fn default() -> LinuxPluginData<'a> {
        LinuxPluginData {
            devs: BTreeMap::new(),
            local_fs: BTreeMap::new(),
            mpath: BTreeMap::new(),
            vgs: BTreeMap::new(),
            lvs: BTreeMap::new(),
            zfspools: BTreeMap::new(),
            zfsdatasets: BTreeMap::new(),
        }
    }
}

impl<'a> From<&'a ScsiDevice> for LinuxPluginDevice<'a> {
    fn from(s: &ScsiDevice) -> LinuxPluginDevice {
        LinuxPluginDevice {
            major_minor: (&s.major, &s.minor).into(),
            parent: None,
            path: s.paths.get_min().unwrap(),
            paths: s.paths.iter().collect(),
            partition_number: None,
            serial_83: &s.serial,
            serial_80: &s.scsi80,
            size: Some(s.size),
            filesystem_type: &s.filesystem_type,
        }
    }
}

impl<'a> From<(&'a Partition, Option<&LinuxPluginDevice<'a>>)> for LinuxPluginDevice<'a> {
    fn from((x, p): (&'a Partition, Option<&LinuxPluginDevice>)) -> LinuxPluginDevice<'a> {
        LinuxPluginDevice {
            major_minor: (&x.major, &x.minor).into(),
            parent: p.map(|y| y.major_minor.clone()),
            path: x.paths.get_min().unwrap(),
            paths: x.paths.iter().collect(),
            partition_number: Some(x.partition_number),
            serial_83: &None,
            serial_80: &None,
            size: Some(x.size),
            filesystem_type: &x.filesystem_type,
        }
    }
}

impl<'a> From<(&'a Mpath, Option<&LinuxPluginDevice<'a>>)> for LinuxPluginDevice<'a> {
    fn from((x, _p): (&'a Mpath, Option<&LinuxPluginDevice>)) -> LinuxPluginDevice<'a> {
        LinuxPluginDevice {
            major_minor: (&x.major, &x.minor).into(),
            // @FIXME
            // linux.py erroneously declares that
            // only partitions should have a parent.
            // To make interop work with this assumption
            // we set the parent to `None`.
            // https://github.com/whamcloud/integrated-manager-for-lustre/blob/841567bb99edde5b635fb1573a6485f6eb75428a/chroma_core/plugins/linux.py#L439
            parent: None,
            path: x.paths.get_min().unwrap(),
            paths: x.paths.iter().collect(),
            partition_number: None,
            serial_83: &x.serial,
            serial_80: &x.scsi80,
            size: Some(x.size),
            filesystem_type: &x.filesystem_type,
        }
    }
}

impl<'a> From<(&'a LogicalVolume, Option<&LinuxPluginDevice<'a>>)> for LinuxPluginDevice<'a> {
    fn from((x, _p): (&'a LogicalVolume, Option<&LinuxPluginDevice>)) -> LinuxPluginDevice<'a> {
        LinuxPluginDevice {
            major_minor: ("lv", &x.uuid).into(),
            // @FIXME
            // linux.py erroneously declares that
            // only partitions should have a parent.
            // To make interop work with this assumption
            // we set the parent to `None`.
            // https://github.com/whamcloud/integrated-manager-for-lustre/blob/841567bb99edde5b635fb1573a6485f6eb75428a/chroma_core/plugins/linux.py#L439
            parent: None,
            path: x.paths.get_min().unwrap(),
            paths: x.paths.iter().collect(),
            partition_number: None,
            serial_83: &None,
            serial_80: &None,
            size: Some(x.size),
            filesystem_type: &x.filesystem_type,
        }
    }
}

impl<'a> From<&'a Zpool> for LinuxPluginZpool<'a> {
    fn from(x: &'a Zpool) -> LinuxPluginZpool<'a> {
        LinuxPluginZpool {
            name: &x.name,
            path: &x.name,
            block_device: ("zfspool", &x.guid).into(),
            size: x.size,
            uuid: x.guid,
            drives: BTreeSet::new(),
        }
    }
}

impl<'a> From<(&'a Dataset, u64)> for LinuxPluginZpool<'a> {
    fn from((x, size): (&'a Dataset, u64)) -> LinuxPluginZpool<'a> {
        LinuxPluginZpool {
            name: &x.name,
            path: &x.name,
            block_device: ("zfsset", &x.guid).into(),
            size,
            uuid: x.guid,
            drives: BTreeSet::new(),
        }
    }
}

fn add_mount<'a>(
    mount: &'a Mount,
    d: &LinuxPluginDevice<'a>,
    linux_plugin_data: &mut LinuxPluginData<'a>,
) {
    // This check is working around one cause of https://github.com/whamcloud/integrated-manager-for-lustre/issues/895
    // Once we persist device-scanner input directly in the IML database, we won't need this fn anymore,
    // as device-scanner correctly reports that the mount is transient.
    if mount.target.0.as_os_str().len() == 14
        && mount.target.0.to_string_lossy().starts_with("/tmp/mnt")
    {
        return;
    }

    linux_plugin_data
        .local_fs
        .insert(d.major_minor.clone(), (&mount.target, &mount.fs_type));
}

pub fn populate_zpool<'a>(
    x: &'a Zpool,
    mm: MajorMinor,
    linux_plugin_data: &mut LinuxPluginData<'a>,
) {
    if x.children.is_empty() {
        let pool = linux_plugin_data
            .devs
            .entry(("zfspool", x.guid).into())
            .or_insert_with(|| LinuxPluginItem::LinuxPluginZpool(x.into()));

        if let LinuxPluginItem::LinuxPluginZpool(p) = pool {
            p.drives.insert(mm.clone());

            let p2 = linux_plugin_data
                .zfspools
                .entry(p.uuid)
                .or_insert_with(|| p.clone());

            p2.drives.insert(mm);
        };
    } else {
        for dev in &x.children {
            if let Device::Dataset(d) = dev {
                let dataset = linux_plugin_data
                    .devs
                    .entry(("zfsset", d.guid).into())
                    .or_insert_with(|| LinuxPluginItem::LinuxPluginZpool((d, x.size).into()));

                if let LinuxPluginItem::LinuxPluginZpool(d) = dataset {
                    d.drives.insert(mm.clone());

                    let d2 = linux_plugin_data
                        .zfsdatasets
                        .entry(d.uuid)
                        .or_insert_with(|| d.clone());

                    d2.drives.insert(mm.clone());
                };
            }
        }
    }
}

pub fn devtree2linuxoutput<'a>(
    device: &'a Device,
    parent: Option<&LinuxPluginDevice<'a>>,
    mut linux_plugin_data: &mut LinuxPluginData<'a>,
) {
    match device {
        Device::Root(x) => {
            for c in &x.children {
                devtree2linuxoutput(c, None, &mut linux_plugin_data);
            }
        }
        Device::ScsiDevice(x) => {
            let d: LinuxPluginDevice = x.into();

            if let Some(mount) = &x.mount {
                add_mount(mount, &d, linux_plugin_data);
            }

            for c in &x.children {
                devtree2linuxoutput(&c, Some(&d), &mut linux_plugin_data);
            }

            linux_plugin_data
                .devs
                .insert(d.major_minor.clone(), LinuxPluginItem::LinuxPluginDevice(d));
        }
        Device::Partition(x) => {
            let d: LinuxPluginDevice = (x, parent).into();

            if let Some(mount) = &x.mount {
                add_mount(mount, &d, linux_plugin_data);
            }

            for c in &x.children {
                devtree2linuxoutput(c, Some(&d), &mut linux_plugin_data);
            }

            linux_plugin_data
                .devs
                .insert(d.major_minor.clone(), LinuxPluginItem::LinuxPluginDevice(d));
        }
        Device::Mpath(x) => {
            let d: LinuxPluginDevice<'a> = (x, parent).into();

            if let Some(mount) = &x.mount {
                add_mount(mount, &d, linux_plugin_data);
            }

            for c in &x.children {
                devtree2linuxoutput(c, Some(&d), &mut linux_plugin_data);
            }

            let block_device = d.major_minor.clone();

            linux_plugin_data
                .devs
                .insert(d.major_minor.clone(), LinuxPluginItem::LinuxPluginDevice(d));

            let mpath_device =
                linux_plugin_data
                    .mpath
                    .entry(&x.dm_name)
                    .or_insert(LinuxPluginMpathDevice {
                        block_device,
                        name: &x.dm_name,
                        nodes: BTreeSet::new(),
                    });

            if let Some(parent) = parent {
                mpath_device.nodes.insert(parent.clone());
            }
        }
        Device::VolumeGroup(x) => {
            let vg_device = linux_plugin_data
                .vgs
                .entry(&x.name)
                .or_insert(LinuxPluginVgDevice {
                    name: &x.name,
                    size: x.size,
                    uuid: &x.uuid,
                    pvs_major_minor: BTreeSet::new(),
                });

            if let Some(parent) = parent {
                vg_device.pvs_major_minor.insert(parent.major_minor.clone());
            }

            x.children
                .iter()
                .filter_map(|d| match d {
                    Device::LogicalVolume(lv) => Some(lv),
                    _ => None,
                })
                .for_each(|lv| {
                    let d: LinuxPluginDevice = (lv, parent).into();

                    if let Some(mount) = &lv.mount {
                        add_mount(mount, &d, linux_plugin_data);
                    }

                    for c in &lv.children {
                        devtree2linuxoutput(c, Some(&d), &mut linux_plugin_data);
                    }

                    let block_device = d.major_minor.clone();

                    linux_plugin_data
                        .devs
                        .insert(d.major_minor.clone(), LinuxPluginItem::LinuxPluginDevice(d));

                    linux_plugin_data
                        .lvs
                        .entry(&x.name)
                        .or_insert_with(BTreeMap::new)
                        .entry(&lv.name)
                        .or_insert(LinuxPluginLvDevice {
                            name: &lv.name,
                            size: lv.size,
                            uuid: &lv.uuid,
                            block_device,
                        });
                });
        }
        Device::Zpool(x) => {
            populate_zpool(x, parent.unwrap().major_minor.clone(), linux_plugin_data);
        }
        _ => {}
    };
}

type PoolMap<'a> = BTreeMap<u64, (&'a Zpool, BTreeSet<DevicePath>)>;

pub fn build_device_lookup<'a>(
    dev_tree: &'a Device,
    path_map: &mut BTreeMap<&'a DevicePath, MajorMinor>,
    pool_map: &mut PoolMap<'a>,
) {
    match dev_tree {
        Device::Root(Root { children }) | Device::VolumeGroup(VolumeGroup { children, .. }) => {
            for c in children {
                build_device_lookup(c, path_map, pool_map);
            }
        }
        Device::ScsiDevice(ScsiDevice {
            children,
            paths,
            major,
            minor,
            ..
        })
        | Device::Partition(Partition {
            children,
            paths,
            major,
            minor,
            ..
        })
        | Device::MdRaid(MdRaid {
            children,
            paths,
            major,
            minor,
            ..
        })
        | Device::Mpath(Mpath {
            children,
            paths,
            major,
            minor,
            ..
        }) => {
            for p in paths {
                path_map.insert(p, (major, minor).into());
            }

            for c in children {
                build_device_lookup(c, path_map, pool_map);
            }
        }
        Device::LogicalVolume(LogicalVolume {
            children,
            paths,
            uuid,
            ..
        }) => {
            for p in paths {
                path_map.insert(p, ("lv", uuid).into());
            }

            for c in children {
                build_device_lookup(c, path_map, pool_map);
            }
        }
        Device::Zpool(x) => {
            let paths = get_vdev_paths(&x.vdev);

            pool_map.entry(x.guid).or_insert_with(|| (x, paths));
        }
        Device::Dataset(_) => {}
    }
}

/// In order for a pool to exist on > 1 node, *all* of it's backing
/// storage must exist on > 1 host.
///
/// This fn figures out if all of a pools VDEVs exist on
/// multiple hosts and if so, returns
/// where they need to be inserted.
pub fn get_shared_pools<'a, S: ::std::hash::BuildHasher>(
    host: &Fqdn,
    path_map: &'a BTreeMap<&'a DevicePath, MajorMinor>,
    cluster_pools: &'a HashMap<&'a Fqdn, PoolMap<'a>, S>,
) -> Vec<(&'a Zpool, MajorMinor)> {
    let mut shared_pools: Vec<_> = vec![];

    let paths: BTreeSet<&DevicePath> = path_map.keys().copied().collect();

    for (&h, ps) in cluster_pools.iter() {
        if host == h {
            continue;
        }

        for v in ps.values() {
            let ds = v.1.iter().collect();

            if !paths.is_superset(&ds) {
                continue;
            };

            tracing::debug!("pool is shared between {} and {}", h, host);

            for d in ds {
                let parent = path_map[&d].clone();

                shared_pools.push((v.0, parent));
            }
        }
    }

    shared_pools
}

/// Given a slice of major minors,
/// figures out all cooresponding the device paths and returns them.
fn major_minors_to_dev_paths<'a>(
    xs: &BTreeSet<MajorMinor>,
    path_map: &BTreeMap<&'a DevicePath, MajorMinor>,
) -> BTreeSet<&'a DevicePath> {
    xs.iter().fold(BTreeSet::new(), |acc, mm| {
        let paths = path_map
            .iter()
            .filter(|(_, pmm)| &mm == pmm)
            .map(|(p, _)| *p)
            .collect();

        acc.union(&paths).copied().collect()
    })
}

/// Given some aggregated data
/// Figure out what VGs can be shared between hosts and add them to the other hosts.
pub fn update_vgs<'a>(
    mut xs: BTreeMap<&'a Fqdn, LinuxPluginData<'a>>,
    path_map: &HashMap<&'a Fqdn, BTreeMap<&'a DevicePath, MajorMinor>>,
) -> BTreeMap<&'a Fqdn, LinuxPluginData<'a>> {
    let shared_vgs = xs.iter().fold(vec![], |mut acc, (from_host, x)| {
        let from_paths = &path_map[from_host];

        let mut others: Vec<_> = xs
            .iter()
            .filter(|(k, _)| k != &from_host)
            .filter_map(|(to_host, _)| {
                let to_paths: BTreeSet<&DevicePath> =
                    (&path_map[to_host]).keys().copied().collect();

                let shared_vgs: Vec<_> = x
                    .vgs
                    .iter()
                    .filter(|(_, vg)| {
                        let p = major_minors_to_dev_paths(&vg.pvs_major_minor, &from_paths);

                        to_paths.is_superset(&p)
                    })
                    .map(|(vg_name, _)| (Fqdn::clone(from_host), Fqdn::clone(to_host), *vg_name))
                    .collect();

                if shared_vgs.is_empty() {
                    None
                } else {
                    Some(shared_vgs)
                }
            })
            .flatten()
            .collect();

        acc.append(&mut others);

        acc
    });

    for (from_host, to_host, vg_name) in shared_vgs {
        let from = xs.get(&from_host).unwrap();

        let vg = from.vgs.get(&vg_name).cloned().unwrap();

        let lvs = from.lvs.get(&vg_name).cloned();

        let lv_devs: Option<Vec<_>> = lvs.as_ref().map(|lvs| {
            lvs.iter()
                .map(|(_, lv)| {
                    (
                        lv.block_device.clone(),
                        from.devs.get(&lv.block_device).cloned().unwrap_or_else(|| {
                            panic!("Did not find lv block device {:?}", lv.block_device)
                        }),
                    )
                })
                .collect()
        });

        let to = xs.get_mut(&to_host).unwrap();

        to.vgs.insert(vg_name, vg);

        if let Some(lvs) = lvs {
            to.lvs.insert(vg_name, lvs);
        }

        if let Some(lv_devs) = lv_devs {
            for (mm, lv_dev) in lv_devs {
                to.devs.insert(mm, lv_dev);
            }
        }
    }

    xs
}

#[cfg(test)]
mod tests {
    use super::{devtree2linuxoutput, LinuxPluginData};
    use device_types::devices::Device;
    use insta::assert_json_snapshot;

    #[test]
    fn test_devtree2linuxoutput() {
        let device: Device =
            serde_json::from_slice(include_bytes!("../fixtures/devtree.json")).unwrap();

        let mut data = LinuxPluginData::default();

        devtree2linuxoutput(&device, None, &mut data);

        assert_json_snapshot!(data);
    }

    #[test]
    fn test_devtree2linuxoutput_zpool() {
        let device: Device =
            serde_json::from_slice(include_bytes!("../fixtures/devtree_zpool.json")).unwrap();

        let mut data = LinuxPluginData::default();

        devtree2linuxoutput(&device, None, &mut data);

        assert_json_snapshot!(data);
    }

    #[test]
    fn test_devtree2linuxoutput_dataset() {
        let device: Device =
            serde_json::from_slice(include_bytes!("../fixtures/devtree_zpool_dataset.json"))
                .unwrap();

        let mut data = LinuxPluginData::default();

        devtree2linuxoutput(&device, None, &mut data);

        assert_json_snapshot!(data);
    }
}


text:
#ifndef _ASM_SOCKET_H
#define _ASM_SOCKET_H

#include <asm/sockios.h>

/* For setsockoptions(2) */
#define SOL_SOCKET	1

#define SO_DEBUG	1
#define SO_REUSEADDR	2
#define SO_TYPE		3
#define SO_ERROR	4
#define SO_DONTROUTE	5
#define SO_BROADCAST	6
#define SO_SNDBUF	7
#define SO_RCVBUF	8
#define SO_KEEPALIVE	9
#define SO_OOBINLINE	10
#define SO_NO_CHECK	11
#define SO_PRIORITY	12
#define SO_LINGER	13
#define SO_BSDCOMPAT	14
/* To add :#define SO_REUSEPORT 15 */

#endif /* _ASM_SOCKET_H */

redpajama_set_name: RedPajamaGithub


text:
<!doctype html>

<meta charset="utf-8">
<title>Dirty Harry: Hacking for free drinks in Singapore – Pankaj Kohli</title>
<meta name="description" content="Harry’s bar is one of the most popular bar chains in Singapore. It has an iOS app “Appy Hour” that lets users spin the Harry’s “wheel of fortune” to win free drinks. The way it works is that a user would visit one of their strategically located bars and check in using the app. He would then spin the wheel, and if he is lucky, he would win a free drink. A time limit is imposed so that a user can spin the wheel only once in 24 hours while signed in a particular bar.

">
<meta name="keywords" content="Appy Hour, free drinks, Harry's bar, iOS, blog">

<meta name="twitter:title" content="Dirty Harry: Hacking for free drinks in Singapore">
<meta name="twitter:description" content="Harry’s bar is one of the most popular bar chains in Singapore. It has an iOS app “Appy Hour” that lets users spin the Harry’s “wheel of fortune” to win free drinks. The way it works is that a user would visit one of their strategically located bars and check in using the app. He would then spin the wheel, and if he is lucky, he would win a free drink. A time limit is imposed so that a user can spin the wheel only once in 24 hours while signed in a particular bar.

">
<meta name="twitter:site" content="@pank4j">
<meta name="twitter:creator" content="@pank4j">

<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/default-thumb.png">

<meta property="og:locale" content="en_US">
<meta property="og:type" content="article">
<meta property="og:title" content="Dirty Harry: Hacking for free drinks in Singapore">
<meta property="og:description" content="Harry’s bar is one of the most popular bar chains in Singapore. It has an iOS app “Appy Hour” that lets users spin the Harry’s “wheel of fortune” to win free drinks. The way it works is that a user would visit one of their strategically located bars and check in using the app. He would then spin the wheel, and if he is lucky, he would win a free drink. A time limit is imposed so that a user can spin the wheel only once in 24 hours while signed in a particular bar.

">
<meta property="og:url" content="/posts/dirty-harry-hacking-for-free-drinks-in-singapore.html">
<meta property="og:site_name" content="Pankaj Kohli">

<meta property="og:image" content="/images/default-thumb.png">

<link rel="canonical" href="/posts/dirty-harry-hacking-for-free-drinks-in-singapore.html">
<link href="/feed.xml" type="application/atom+xml" rel="alternate" title="Pankaj Kohli Feed">

<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link rel="stylesheet" href="/assets/css/main.css">

<meta http-equiv="cleartype" content="on">

<link href='//fonts.googleapis.com/css?family=PT+Sans+Narrow:400,700%7CPT+Serif:400,700,400italic' rel='stylesheet' type='text/css'>

<link rel="shortcut icon" href="/favicon.ico">

<link rel="shortcut icon" href="/favicon.png">

<link rel="apple-touch-icon-precomposed" href="/images/apple-touch-icon-precomposed.png">

<link rel="apple-touch-icon-precomposed" sizes="72x72" href="/images/apple-touch-icon-72x72-precomposed.png">

<link rel="apple-touch-icon-precomposed" sizes="114x114" href="/images/apple-touch-icon-114x114-precomposed.png">

<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/images/apple-touch-icon-144x144-precomposed.png">

		Pankaj Kohli

About

Posts

Archive

Pankaj Kohli

Security Researcher

   Twitter

   LinkedIn

   Github

Dirty Harry: Hacking for free drinks in Singapore

Harry's bar is one of the most popular bar chains in Singapore. It has an iOS app "Appy Hour" that lets users spin the Harry's "wheel of fortune" to win free drinks. The way it works is that a user would visit one of their strategically located bars and check in using the app. He would then spin the wheel, and if he is lucky, he would win a free drink. A time limit is imposed so that a user can spin the wheel only once in 24 hours while signed in a particular bar.

Now there may not be any such thing as a free lunch, but there are free drinks! Let's see how.

The 'luck factor'

The app communicates with www.exhost.se over HTTP. When started, the first thing the app does is to define the "luck factor" of the user, by downloading an XML file containing probabilities of various prizes. The probabilities are set in way such that 52% of the time a spin would yield 'Better Luck Next Time'.

GET /harrys_1_1_beta/venues.xml HTTP/1.1
Host: www.exhost.se
User-Agent: Appy Hour 1.1.0 (iPhone; iPhone OS 6.0.1; en_SG)
Connection: keep-alive
Accept-Encoding: gzip

HTTP/1.1 200 OK
Age: 1659
Connection: Keep-Alive
Content-Length: 3071
Content-Type: application/xml
Date: Fri, 01 Nov 2013 06:27:45 GMT
ETag: "3c8066-bff-4d7ddfaa98300"
Last-Modified: Thu, 14 Mar 2013 08:05:00 GMT
Server: Apache/2.2.22 (Unix) mod_ssl/2.2.22 OpenSSL/0.9.8e-fips-rhel5 DAV/2 mod_bwlimited/1.4 mod_fcgid/2.3.6
Via: 1.1 qt-mfc4:80

<?xml version="1.0" encoding="UTF-8"?>
<Prizes>
<Prize>
<Description>Better Luck*Next Time</Description>
<Units>1</Units>
<ID>1</ID>
<Active>1</Active>
<Possibility>13</Possibility>
<IsPrize>0</IsPrize>
<PrizeFile>img/1.png</PrizeFile>
</Prize>
<Prize>
<Description>1-for-1 Bacardi*Sup Gls</Description>
<Units>1</Units>
<ID>2</ID>
<Active>1</Active>
<Possibility>5</Possibility>
<IsPrize>1</IsPrize>
<PrizeFile>img/2.png</PrizeFile>
</Prize>
--snipped--

Time Restriction

Once the user has checked in the bar, the app checks if the user has already tried his luck in the past 24 hours in the same bar. It does so by sending a request with the iPhone's UDID, a timestamp and the bar's id. The response simply consists of true if the user is allowed to spin the wheel, or false otherwise.

GET /harrys_1_1_beta/fetchdata.php?udid=aba5372762118af8f6f0594f836cd0eb32d10986&time=2013-01-11%02:56:15&venue=30 HTTP/1.1
Host: www.exhost.se
User-Agent: Appy Hour 1.1.0 (iPhone; iPhone OS 6.0.1; en_SG)
Connection: keep-alive
Accept-Encoding: gzip

HTTP/1.1 200 OK
Date: Fri, 01 Nov 2013 06:56:16 GMT
Server: Apache/2.2.22 (Unix) mod_ssl/2.2.22 OpenSSL/0.9.8e-fips-rhel5 DAV/2 mod_bwlimited/1.4 mod_fcgid/2.3.6
X-Powered-By: PHP/5.3.10
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html

true

Getting past everything

Well, the simplest way to get past everything would be to make the app communicate with another server instead of www.exhost.se. First we will crawl www.exhost.se to get all the required files. The link http://www.exhost.se/harrys_1_1_beta/ does not contain a default index.html or similar file, which makes crawling possible.

$ wget -nv -r --no-parent --reject "index.html*" http://www.exhost.se/harrys_1_1_beta/

2013-11-03 23:37:09 URL:http://www.exhost.se/harrys_1_1_beta/ [639/639] -> /"www.exhost.se/harrys_1_1_beta/index.html" [1]
http://www.exhost.se/robots.txt:
2013-11-03 23:37:09 ERROR 404: Not Found.
2013-11-03 23:37:10 URL:http://www.exhost.se/harrys_1_1_beta/cms.php [169] -> "www.exhost.se/harrys_1_1_beta/cms.php" [1]
2013-11-03 23:37:10 URL:http://www.exhost.se/harrys_1_1_beta/connect.php [0/0] -> "www.exhost.se/harrys_1_1_beta/connect.php" [1]
2013-11-03 23:37:10 URL:http://www.exhost.se/harrys_1_1_beta/fetchdata.php [5] -> "www.exhost.se/harrys_1_1_beta/fetchdata.php" [1]
2013-11-03 23:37:11 URL:http://www.exhost.se/harrys_1_1_beta/img/ [1037/1037] -> "www.exhost.se/harrys_1_1_beta/img/index.html" [1]
2013-11-03 23:37:11 URL:http://www.exhost.se/harrys_1_1_beta/js/ [461/461] -> "www.exhost.se/harrys_1_1_beta/js/index.html" [1]
2013-11-03 23:37:12 URL:http://www.exhost.se/harrys_1_1_beta/venues.xml [3071/3071] -> "www.exhost.se/harrys_1_1_beta/venues.xml" [1]
2013-11-03 23:37:19 URL:http://www.exhost.se/harrys_1_1_beta/img/1.png [50769/50769] -> "www.exhost.se/harrys_1_1_beta/img/1.png" [1]
2013-11-03 23:37:23 URL:http://www.exhost.se/harrys_1_1_beta/img/10.png [62543/62543] -> "www.exhost.se/harrys_1_1_beta/img/10.png" [1]
2013-11-03 23:37:24 URL:http://www.exhost.se/harrys_1_1_beta/img/11.png [23376/23376] -> "www.exhost.se/harrys_1_1_beta/img/11.png" [1]
2013-11-03 23:37:26 URL:http://www.exhost.se/harrys_1_1_beta/img/12.png [33471/33471] -> "www.exhost.se/harrys_1_1_beta/img/12.png" [1]
2013-11-03 23:37:29 URL:http://www.exhost.se/harrys_1_1_beta/img/13.png [58419/58419] -> "www.exhost.se/harrys_1_1_beta/img/13.png" [1]
2013-11-03 23:37:31 URL:http://www.exhost.se/harrys_1_1_beta/img/14.png [50769/50769] -> "www.exhost.se/harrys_1_1_beta/img/14.png" [1]
2013-11-03 23:37:32 URL:http://www.exhost.se/harrys_1_1_beta/img/15.png [50119/50119] -> "www.exhost.se/harrys_1_1_beta/img/15.png" [1]
2013-11-03 23:37:33 URL:http://www.exhost.se/harrys_1_1_beta/img/16.png [23376/23376] -> "www.exhost.se/harrys_1_1_beta/img/16.png" [1]
2013-11-03 23:37:34 URL:http://www.exhost.se/harrys_1_1_beta/img/2.png [44208/44208] -> "www.exhost.se/harrys_1_1_beta/img/2.png" [1]
2013-11-03 23:37:36 URL:http://www.exhost.se/harrys_1_1_beta/img/3.png [62543/62543] -> "www.exhost.se/harrys_1_1_beta/img/3.png" [1]
2013-11-03 23:37:38 URL:http://www.exhost.se/harrys_1_1_beta/img/4.png [50769/50769] -> "www.exhost.se/harrys_1_1_beta/img/4.png" [1]
2013-11-03 23:37:40 URL:http://www.exhost.se/harrys_1_1_beta/img/5.png [60030/60030] -> "www.exhost.se/harrys_1_1_beta/img/5.png" [1]
2013-11-03 23:37:44 URL:http://www.exhost.se/harrys_1_1_beta/img/6.jpg [124823/124823] -> "www.exhost.se/harrys_1_1_beta/img/6.jpg" [1]
2013-11-03 23:37:46 URL:http://www.exhost.se/harrys_1_1_beta/img/6.png [50119/50119] -> "www.exhost.se/harrys_1_1_beta/img/6.png" [1]
2013-11-03 23:37:47 URL:http://www.exhost.se/harrys_1_1_beta/img/7.png [45129/45129] -> "www.exhost.se/harrys_1_1_beta/img/7.png" [1]
2013-11-03 23:37:49 URL:http://www.exhost.se/harrys_1_1_beta/img/8.png [50769/50769] -> "www.exhost.se/harrys_1_1_beta/img/8.png" [1]
2013-11-03 23:37:50 URL:http://www.exhost.se/harrys_1_1_beta/img/9.png [40394/40394] -> "www.exhost.se/harrys_1_1_beta/img/9.png" [1]
2013-11-03 23:37:52 URL:http://www.exhost.se/harrys_1_1_beta/js/jquery.min.js [85925/85925] -> "www.exhost.se/harrys_1_1_beta/js/jquery.min.js" [1]
FINISHED --2013-11-03 23:37:52--
Total wall clock time: 54s
Downloaded: 25 files, 950K in 34s (28.1 KB/s)

iPhone:~ root# strings -o /var/mobile/Applications/0B57A351-CE6D-4B05-A5D0-8B12BB150791/Harrys.app/Harrys | grep "http://www.exhost.se"
839501 http://www.exhost.se/harrys_1_1_beta/
842849 http://www.exhost.se/harrys_1_1_beta/venues.xml
843075 http://www.exhost.se/harrys_1_1_beta/fetchdata.php

Once we have the crawled files, we can edit the venues.xml file to change the probabilities. We can even change the drinks! ;-) Also, the file fetchdata.php should contain true for us to spin any number of times. Now these files can be hosted on a different server and these URLs can be changed in the app mach-o binary. Changing only the above two URLs is sufficient to make it work without any restrictions. The strings utility comes handy when trying to find out the location of these strings in the binary. These strings can now be edited using a hex editor.

Strings as seen in the disassembler after modification

Once edited, we can run the app any number of times while signed in the same bar, and win a drink on every spin!

Cheers!

Share on

     Twitter

       Facebook

       Google+

Dirty Harry: Hacking for free drinks in Singapore was published on <time datetime="2013-11-04T00:38:07+08:00">November 04, 2013</time>.

You might also enjoy (View all posts)

Solving Team SIK's Android Hacking Event 2016 challenge

Converting IDA Pro graphs to images

AppMinder jailbreak detection analysis

© 2016 Pankaj Kohli. Powered by Jekyll using the Minimal Mistakes theme.

Please enable JavaScript to view the comments powered by Disqus.


text:
<!DOCTYPE html>

    <title>pedalboard.js - Open-source JavaScript framework for developing audio effects for guitars</title>
    <meta name='viewport' content='user-scalable=no'/>
    <meta name='apple-mobile-web-app-capable' content='yes'/>
    <meta name='apple-mobile-web-app-status-bar-style' content='black-translucent'/>

    <link rel="stylesheet" href="css/reset.css"/>
    <link rel="stylesheet" href="css/common.css"/>
    <link rel="stylesheet" href="css/box.css"/>
    <link rel="stylesheet" href="css/switch.css"/>
    <link rel="stylesheet" href="css/pot.css"/>
    <link href='http://fonts.googleapis.com/css?family=Damion' rel='stylesheet' type='text/css'>
    <link href='http://fonts.googleapis.com/css?family=Yellowtail' rel='stylesheet' type='text/css'>
    <link href='http://fonts.googleapis.com/css?family=Radley:400,400italic' rel='stylesheet' type='text/css'>

             PEDALBOARD.JS

▶

Line-in (careful, it's too hot!)

Sample 1

Sample 2

Sample 3

Sample 4

Sample 5


text:
package org.nutz.mvc.init.conf;

import org.nutz.mvc.annotation.Modules;
import org.nutz.mvc.init.module.AtMapModule;
import org.nutz.mvc.init.module.SimpleTestModule;

@Modules(value={AtMapModule.class, SimpleTestModule.class}, scanPackage=false)
public class MainModuleAtMap {}


text:
require 'grape-entity'
require_relative './image_entity'

class StatusEntity < Grape::Entity
  format_with(:iso_timestamp, &:iso8601)

  expose :user_name
  expose :text, documentation: { type: 'String', desc: 'Status update text.' }
  expose :ip, if: { type: :full }
  expose :user_type, :user_id, if: ->(status, _options) { status.user.public? }
  expose :contact_info do
    expose :phone
    expose :address, using: ImageEntity
  end
  expose :digest do |status, _options|
    Digest::MD5.hexdigest status.txt
  end
  expose :replies, using: StatusEntity, as: :responses

  expose :last_reply, using: StatusEntity do |status, _options|
    status.replies.last
  end

  expose :list, documentation: { type: 'Array', desc: 'List of elements' } do
    expose :option_a do
      expose :option_b, documentation: { type: 'Array', desc: 'An option' }
    end

    expose :option_c, documentation: { type: 'Integer', desc: 'Last option' }
  end

  with_options(format_with: :iso_timestamp) do
    expose :created_at
    expose :updated_at
  end
end


text:
require 'spec_helper'

describe RuboCop::Cop::Style::EmptyLinesAroundAccessModifier do
  subject(:cop) { described_class.new }

  %w(private protected public module_function).each do |access_modifier|
    it "requires blank line before #{access_modifier}" do
      inspect_source(cop,
                     ['class Test',
                      '  something',
                      "  #{access_modifier}",
                      '',
                      '  def test; end',
                      'end'])
      expect(cop.offenses.size).to eq(1)
      expect(cop.messages)
        .to eq(["Keep a blank line before and after `#{access_modifier}`."])
    end

    it "requires blank line after #{access_modifier}" do
      inspect_source(cop,
                     ['class Test',
                      '  something',
                      '',
                      "  #{access_modifier}",
                      '  def test; end',
                      'end'])
      expect(cop.offenses.size).to eq(1)
      expect(cop.messages)
        .to eq(["Keep a blank line before and after `#{access_modifier}`."])
    end

    it "autocorrects blank line before #{access_modifier}" do
      corrected = autocorrect_source(cop,
                                     ['class Test',
                                      '  something',
                                      "  #{access_modifier}",
                                      '',
                                      '  def test; end',
                                      'end'])
      expect(corrected).to eq(['class Test',
                               '  something',
                               '',
                               "  #{access_modifier}",
                               '',
                               '  def test; end',
                               'end'].join("\n"))
    end

    it 'autocorrects blank line after #{access_modifier}' do
      corrected = autocorrect_source(cop,
                                     ['class Test',
                                      '  something',
                                      '',
                                      "  #{access_modifier}",
                                      '  def test; end',
                                      'end'])
      expect(corrected).to eq(['class Test',
                               '  something',
                               '',
                               "  #{access_modifier}",
                               '',
                               '  def test; end',
                               'end'].join("\n"))
    end

    it 'accepts missing blank line when at the beginning of class/module' do
      inspect_source(cop,
                     ['class Test',
                      "  #{access_modifier}",
                      '',
                      '  def test; end',
                      'end'])
      expect(cop.offenses).to be_empty
    end

    it 'accepts missing blank line when at the end of block' do
      inspect_source(cop,
                     ['class Test',
                      '  def test; end',
                      '',
                      "  #{access_modifier}",
                      'end'])
      expect(cop.offenses).to be_empty
    end

    it 'recognizes blank lines with DOS style line endings' do
      inspect_source(cop,
                     ["class Test\r",
                      "\r",
                      "  #{access_modifier}\r",
                      "\r",
                      "  def test; end\r",
                      "end\r"])
      expect(cop.offenses.size).to eq(0)
    end
  end
end


text:
#include <cetty/gearman/protobuf/GearmanProtobufClientFilter.h>

#include <string>

#include <cetty/util/StringUtil.h>
#include <cetty/buffer/Unpooled.h>
#include <cetty/gearman/protocol/GearmanMessage.h>
#include <cetty/gearman/protocol/commands/Client.h>

#include <cetty/protobuf/service/ProtobufServiceMessage.h>
#include <cetty/protobuf/service/handler/MessageCodec.h>

namespace cetty {
namespace gearman {
namespace protobuf {

using namespace cetty::util;
using namespace cetty::channel;
using namespace cetty::buffer;
using namespace cetty::gearman::protobuf;
using namespace cetty::protobuf::service;
using namespace cetty::protobuf::service::handler;

GearmanProtobufClientFilter::GearmanProtobufClientFilter()
    : background_(false) {
    filter_.setRequestFilter(boost::bind(&GearmanProtobufClientFilter::filterRequest,
                                         this,
                                         _1,
                                         _2));
    filter_.setResponseFilter(boost::bind(&GearmanProtobufClientFilter::filterResponse,
                                          this,
                                          _1,
                                          _2,
                                          _3));
}

GearmanProtobufClientFilter::~GearmanProtobufClientFilter() {
}

GearmanMessagePtr GearmanProtobufClientFilter::filterRequest(
    ChannelHandlerContext& ctx,
    const ProtobufServiceMessagePtr& req) {
    std::string method;
    req->methodFullName(&method);

    ChannelBufferPtr buffer
        = Unpooled::buffer(req->messageSize() + 8);

    //encode the protobufServiceMessage and set it to GearmanMessage
    MessageCodec::encodeMessage(req, buffer);

    if (background_) {
        return commands::submitJobBGMessage(method,
                                            getUniqueId(req->id()),
                                            buffer);
    }
    else {
        return commands::submitJobMessage(method,
                                          getUniqueId(req->id()),
                                          buffer);
    }
}

const std::string& GearmanProtobufClientFilter::getUniqueId(int64_t id) {
    if (uniqueKey_.empty()) {
        return uniqueKey_;
    }
    else {
        uniqueId_ = uniqueKey_;
        StringUtil::numtostr(id, &uniqueId_);
        return uniqueId_;
    }
}

ProtobufServiceMessagePtr GearmanProtobufClientFilter::filterResponse(
    ChannelHandlerContext& ctx,
    const ProtobufServiceMessagePtr& req,
    const GearmanMessagePtr& rep) {

    //decode from GearmanMessage
    ProtobufServiceMessagePtr protoMsg(new ProtobufServiceMessage);
    MessageCodec::decodeMessage(rep->data(), protoMsg);
    return protoMsg;
}

}
}
}


text:
<!DOCTYPE html>

	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<title>Solution</title>

For output, please, see your browser`s Console!

To change input values modify the variables at the top in the .js file!!!

Hit refresh button or F5 to restart task!

		### Problem 5. Youngest person
*	Write a function that finds the youngest person in a given array of people and prints his/hers full name
*	Each person has properties firstname, lastname and age.


text:
var fs = require('fs');
var vm = require('vm');
var loadVendor = function(js) {
    vm.runInThisContext(fs.readFileSync(__dirname+'/../vendor/'+js), js);
}.bind(this);

loadVendor('jszip/jszip.js');
loadVendor('jszip/jszip-deflate.js');
loadVendor('jszip/jszip-inflate.js');
loadVendor('jszip/jszip-load.js');

module.exports = function(data, options) { return new JSZip(data, options) };


text:
namespace LottieUWP.Value
{
    /// <summary>
    /// Data class for use with <see cref="LottieValueCallback{T}"/>.
    /// You should* not* hold a reference to the frame info parameter passed to your callback. It will be reused.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class LottieFrameInfo<T>
    {
        internal LottieFrameInfo<T> Set(
            float startFrame,
            float endFrame,
            T startValue,
            T endValue,
            float linearKeyframeProgress,
            float interpolatedKeyframeProgress,
            float overallProgress
        )
        {
            StartFrame = startFrame;
            EndFrame = endFrame;
            StartValue = startValue;
            EndValue = endValue;
            LinearKeyframeProgress = linearKeyframeProgress;
            InterpolatedKeyframeProgress = interpolatedKeyframeProgress;
            OverallProgress = overallProgress;
            return this;
        }

        public float StartFrame { get; private set; }

        public float EndFrame { get; private set; }

        public T StartValue { get; private set; }

        public T EndValue { get; private set; }

        public float LinearKeyframeProgress { get; private set; }

        public float InterpolatedKeyframeProgress { get; private set; }

        public float OverallProgress { get; private set; }
    }
}


text:
package org.motechproject.sms.http.it;

import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.servlet.DispatcherServlet;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:META-INF/motech/*.xml"})
public class ControllerIT {
    @Test
    @Ignore("test with telecom provider and app context")
    public void handleIncomingSms() throws Exception {
        Server server = new Server(8080);
        Context context = new Context(server, "/", Context.SESSIONS);

        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        dispatcherServlet.setContextConfigLocation("classpath*:META-INF/motech/*.xml");

        ServletHolder servletHolder = new ServletHolder(dispatcherServlet);
        context.addServlet(servletHolder, "/*");

        server.start();
        server.join();
        Thread.sleep(1000000);
    }

}


text:
int omap_sram_init(void);

void omap_map_sram(unsigned long start, unsigned long size,
			unsigned long skip, int cached);
void omap_sram_reset(void);

extern void *omap_sram_push_address(unsigned long size);

/* Macro to push a function to the internal SRAM, using the fncpy API */
#define omap_sram_push(funcp, size) ({				\
	typeof(&(funcp)) _res = NULL;				\
	void *_sram_address = omap_sram_push_address(size);	\
	if (_sram_address)					\
		_res = fncpy(_sram_address, &(funcp), size);	\
	_res;							\
})


text:
package daemon

import (
	"fmt"

	"github.com/docker/docker/api/types"
)

func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error) {
	container, err := daemon.Get(name)
	if err != nil {
		return nil, err
	}

	container.Lock()
	defer container.Unlock()

	base, err := daemon.getInspectData(container)
	if err != nil {
		return nil, err
	}

	return &types.ContainerJSON{base, container.Config}, nil
}

func (daemon *Daemon) ContainerInspectRaw(name string) (*types.ContainerJSONRaw, error) {
	container, err := daemon.Get(name)
	if err != nil {
		return nil, err
	}

	container.Lock()
	defer container.Unlock()

	base, err := daemon.getInspectData(container)
	if err != nil {
		return nil, err
	}

	config := &types.ContainerConfig{
		container.Config,
		container.hostConfig.Memory,
		container.hostConfig.MemorySwap,
		container.hostConfig.CpuShares,
		container.hostConfig.CpusetCpus,
	}

	return &types.ContainerJSONRaw{base, config}, nil
}

func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSONBase, error) {
	// make a copy to play with
	hostConfig := *container.hostConfig

	if children, err := daemon.Children(container.Name); err == nil {
		for linkAlias, child := range children {
			hostConfig.Links = append(hostConfig.Links, fmt.Sprintf("%s:%s", child.Name, linkAlias))
		}
	}
	// we need this trick to preserve empty log driver, so
	// container will use daemon defaults even if daemon change them
	if hostConfig.LogConfig.Type == "" {
		hostConfig.LogConfig = daemon.defaultLogConfig
	}

	containerState := &types.ContainerState{
		Running:    container.State.Running,
		Paused:     container.State.Paused,
		Restarting: container.State.Restarting,
		OOMKilled:  container.State.OOMKilled,
		Dead:       container.State.Dead,
		Pid:        container.State.Pid,
		ExitCode:   container.State.ExitCode,
		Error:      container.State.Error,
		StartedAt:  container.State.StartedAt,
		FinishedAt: container.State.FinishedAt,
	}

	volumes := make(map[string]string)
	volumesRW := make(map[string]bool)

	for _, m := range container.MountPoints {
		volumes[m.Destination] = m.Path()
		volumesRW[m.Destination] = m.RW
	}

	contJSONBase := &types.ContainerJSONBase{
		Id:              container.ID,
		Created:         container.Created,
		Path:            container.Path,
		Args:            container.Args,
		State:           containerState,
		Image:           container.ImageID,
		NetworkSettings: container.NetworkSettings,
		ResolvConfPath:  container.ResolvConfPath,
		HostnamePath:    container.HostnamePath,
		HostsPath:       container.HostsPath,
		LogPath:         container.LogPath,
		Name:            container.Name,
		RestartCount:    container.RestartCount,
		Driver:          container.Driver,
		ExecDriver:      container.ExecDriver,
		MountLabel:      container.MountLabel,
		ProcessLabel:    container.ProcessLabel,
		Volumes:         volumes,
		VolumesRW:       volumesRW,
		AppArmorProfile: container.AppArmorProfile,
		ExecIDs:         container.GetExecIDs(),
		HostConfig:      &hostConfig,
	}

	return contJSONBase, nil
}

func (daemon *Daemon) ContainerExecInspect(id string) (*execConfig, error) {
	eConfig, err := daemon.getExecConfig(id)
	if err != nil {
		return nil, err
	}

	return eConfig, nil
}


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Mycologia 50(5): 655 (1958)

#### Original name
Stictis myricae E.K. Cash

### Remarks
null


text:
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="data:text/css,root%2C%20observe%2C%20outside%20%7Bdisplay%3Ablock%7Doutside%20%7Bmargin-left%3A-4em%7D"?>
<root>
<observe>There should be only one sentence on this page.</observe>
<outside>FAIL</outside>
</root>
<!--
root, observe, outside {display:block}
outside {margin-left:-4em}
-->


text:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.8/css/materialize.min.css">

Sign in

New account

        <form class="cd-form">

             Sign in with Google

             Sign in with Facebook

        </form>

      Close

  Login / Register

Project name goes here

Welcome to use our team-formation platform. The best platform you and your team ever met.

Project name goes here

Welcome to use our team-formation platform. The best platform you and your team ever met.

This is the tutorial video with eye-catching features enphasized below

<feature-card ng-repeat="feature in features"></feature-card>

Developer Info

<developer-card ng-repeat="developer in developers"></developer-card>

Welcome to the best online-teamform-platform in this galaxy ! Congratulations !


text:
<?php
/*
	template name: 读者墙
	description: template for G theme
*/
get_header();
function readers_wall( $outer='1',$timer='100',$limit='60' ){
	global $wpdb;
	$counts = $wpdb->get_results("select count(comment_author) as cnt, comment_author, comment_author_url, comment_author_email from (select * from $wpdb->comments left outer join $wpdb->posts on ($wpdb->posts.id=$wpdb->comments.comment_post_id) where comment_date > date_sub( now(), interval $timer month ) and user_id='0' and comment_author != '".$outer."' and post_password='' and comment_approved='1' and comment_type='') as tempcmt group by comment_author order by cnt desc limit $limit");
	foreach ($counts as $count) {
		$c_url = $count->comment_author_url;
		if (!$c_url) $c_url = 'javascript:;';
		$type .= 'comment_author.']近期评论'. $count->cnt . '次">'.get_avatar( $count->comment_author_email, $size = '64' , deel_avatar_default() ).''.$count->comment_author.'';
	}
	echo $type;
};
?>

			<?php echo str_replace("

", "", preg_replace("/
]*>
]*>/", "", wp_nav_menu(array('theme_location' => 'pagemenu', 'echo' => false)) )); ?>

				<a href="<?php the_permalink() ?>"><?php the_title(); ?>

				<?php deel_share() ?>

		<?php while (have_posts()) : the_post(); ?>

				<?php the_content(); ?>

				<?php readers_wall(); ?>

		<?php comments_template('', true); endwhile;  ?>

<?php get_footer(); ?>


text:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/Pic"
        android:showAsAction="never"
        android:title="添加图片"/>
 	<item
        android:id="@+id/Sound"
        android:showAsAction="never"
        android:title="添加声音"/>
 	<item
        android:id="@+id/Remind"
        android:showAsAction="never"
        android:title="设置提醒"/>
</menu>


text:
$(document).ready(function() {
    $('#logTable').DataTable();
} );


text:
package com.jpm.stocks.model;

/**
 * Trade Type enum
 *
 * @author Vadims Krivcovs
 */
public enum TradeType {
	BUY,
	SELL
}


text:
package ro.nextreports.server.web.core.menu;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.wicket.injection.Injector;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.spring.injection.annot.SpringBean;

import ro.nextreports.server.domain.Entity;
import ro.nextreports.server.web.common.menu.MenuItem;
import ro.nextreports.server.web.common.menu.MenuPanel;
import ro.nextreports.server.web.core.action.ActionContributor;
import ro.nextreports.server.web.core.action.DefaultActionContext;
import ro.nextreports.server.web.core.section.EntitySection;
import ro.nextreports.server.web.core.section.SectionManager;

/**
 * @author Decebal Suiu
 */
public class EntityPopupMenuModel extends LoadableDetachableModel<List<MenuItem>> {

	private static final long serialVersionUID = 1L;

	private IModel<Entity> entityModel;
	private String sectionId;

	@SpringBean
	private SectionManager sectionManager;

	public EntityPopupMenuModel(IModel<Entity> entityModel, String sectionId) {
		Injector.get().inject(this);

		this.entityModel = entityModel;
		this.sectionId = sectionId;
	}

	@Override
	protected List<MenuItem> load() {
        List<MenuItem> menuItems = new ArrayList<>();

        Entity entity = entityModel.getObject();
        DefaultActionContext actionContext = new DefaultActionContext();
        actionContext.setLinkId(MenuPanel.LINK_ID);
        actionContext.setEntity(entity);

        EntitySection entitySection = (EntitySection) sectionManager.getSection(sectionId);
        List<ActionContributor> popupContributors = entitySection.getPopupContributors();
        if (popupContributors != null) {
        	for (ActionContributor contributor : popupContributors) {
        		if (contributor.isVisible() && contributor.support(actionContext.getEntities())) {
        			menuItems.add(new MenuItem(contributor.getLink(actionContext),
        					contributor.getActionName(),  contributor.getActionImage()));
        		}
        	}
        }

        // TODO bootstrap
        MenuItem menuItem = new MenuItem("images/actions.png", null);
//        MenuItem menuItem = new MenuItem("cog", null);
        menuItem.setMenuItems(menuItems);

        return Arrays.asList(menuItem);
	}

}


text:
/*
 * SignedDistanceField.hpp
 *
 *  Created on: Aug 16, 2017
 *     Authors: Takahiro Miki, Peter Fankhauser
 *   Institute: ETH Zurich, ANYbotics
 */

#include <grid_map_sdf/SignedDistanceField.hpp>
#include <grid_map_sdf/distance_transform/dt.h>

#include <grid_map_core/GridMap.hpp>

#include <limits>

using namespace distance_transform;

namespace grid_map {

SignedDistanceField::SignedDistanceField()
    : maxDistance_(std::numeric_limits<float>::max()),
      zIndexStartHeight_(0.0),
      resolution_(0.0),
      lowestHeight_(-1e5) // We need some precision.
{
}

SignedDistanceField::~SignedDistanceField()
{
}

void SignedDistanceField::calculateSignedDistanceField(const GridMap& gridMap, const std::string& layer,
                                                       const double heightClearance)
{
  data_.clear();
  resolution_ = gridMap.getResolution();
  position_ = gridMap.getPosition();
  size_ = gridMap.getSize();
  Matrix map = gridMap.get(layer); // Copy!

  float minHeight = map.minCoeffOfFinites();
  if (!std::isfinite(minHeight)) minHeight = lowestHeight_;
  float maxHeight = map.maxCoeffOfFinites();
  if (!std::isfinite(maxHeight)) maxHeight = lowestHeight_;

  const float valueForEmptyCells = lowestHeight_; // maxHeight, minHeight (TODO Make this an option).
  for (Eigen::Index i{0}; i < map.size(); ++i) {
    if (std::isnan(map(i))) map(i) = valueForEmptyCells;
  }

  // Height range of the signed distance field is higher than the max height.
  maxHeight += heightClearance;

  Matrix sdfElevationAbove = Matrix::Ones(map.rows(), map.cols()) * maxDistance_;
  Matrix sdfLayer = Matrix::Zero(map.rows(), map.cols());
  std::vector<Matrix> sdf;
  zIndexStartHeight_ = minHeight;

  // Calculate signed distance field from bottom.
  for (float h = minHeight; h < maxHeight; h += resolution_) {
    Eigen::Matrix<bool, Eigen::Dynamic, Eigen::Dynamic> obstacleFreeField = map.array() < h;
    Eigen::Matrix<bool, Eigen::Dynamic, Eigen::Dynamic> obstacleField = obstacleFreeField.array() < 1;
    Matrix sdfObstacle = getPlanarSignedDistanceField(obstacleField);
    Matrix sdfObstacleFree = getPlanarSignedDistanceField(obstacleFreeField);
    Matrix sdf2d;
    // If 2d sdfObstacleFree calculation failed, neglect this SDF
    // to avoid extreme small distances (-INF).
    if ((sdfObstacleFree.array() >= INF).any()) sdf2d = sdfObstacle;
    else sdf2d = sdfObstacle - sdfObstacleFree;
    sdf2d *= resolution_;
    for (Eigen::Index i{0}; i < sdfElevationAbove.size(); ++i) {
      if(sdfElevationAbove(i) == maxDistance_ && map(i) <= h) sdfElevationAbove(i) = h - map(i);
      else if(sdfElevationAbove(i) != maxDistance_ && map(i) <= h) sdfElevationAbove(i) = sdfLayer(i) + resolution_;
      if (sdf2d(i) == 0) sdfLayer(i) = h - map(i);
      else if (sdf2d(i) < 0) sdfLayer(i) = -std::min(fabs(sdf2d(i)), fabs(map(i) - h));
      else sdfLayer(i) = std::min(sdf2d(i), sdfElevationAbove(i));
    }
    data_.push_back(sdfLayer);
  }
}

grid_map::Matrix SignedDistanceField::getPlanarSignedDistanceField(Eigen::Matrix<bool, Eigen::Dynamic, Eigen::Dynamic>& data) const
{
  image<uchar> *input = new image<uchar>(data.rows(), data.cols(), true);

  for (int y = 0; y < input->height(); y++) {
    for (int x = 0; x < input->width(); x++) {
      imRef(input, x, y) = data(x, y);
    }
  }

  // Compute dt.
  image<float> *out = dt(input);

  Matrix result(data.rows(), data.cols());

  // Take square roots.
  for (int y = 0; y < out->height(); y++) {
    for (int x = 0; x < out->width(); x++) {
      result(x, y) = sqrt(imRef(out, x, y));
    }
  }
  delete input;
  delete out;
  return result;
}

double SignedDistanceField::getDistanceAt(const Position3& position) const
{
  double xCenter = size_.x() / 2.0;
  double yCenter = size_.y() / 2.0;
  int i = std::round(xCenter - (position.x() - position_.x()) / resolution_);
  int j = std::round(yCenter - (position.y() - position_.y()) / resolution_);
  int k = std::round((position.z() - zIndexStartHeight_) / resolution_);
  i = std::max(i, 0);
  i = std::min(i, size_.x() - 1);
  j = std::max(j, 0);
  j = std::min(j, size_.y() - 1);
  k = std::max(k, 0);
  k = std::min(k, (int)data_.size() - 1);
  return data_[k](i, j);
}

double SignedDistanceField::getInterpolatedDistanceAt(const Position3& position) const
{
  double xCenter = size_.x() / 2.0;
  double yCenter = size_.y() / 2.0;
  int i = std::round(xCenter - (position.x() - position_.x()) / resolution_);
  int j = std::round(yCenter - (position.y() - position_.y()) / resolution_);
  int k = std::round((position.z() - zIndexStartHeight_) / resolution_);
  i = std::max(i, 0);
  i = std::min(i, size_.x() - 1);
  j = std::max(j, 0);
  j = std::min(j, size_.y() - 1);
  k = std::max(k, 0);
  k = std::min(k, (int)data_.size() - 1);
  Vector3 gradient = getDistanceGradientAt(position);
  double xp = position_.x() + ((size_.x() - i) - xCenter) * resolution_;
  double yp = position_.y() + ((size_.y() - j) - yCenter) * resolution_;
  double zp = zIndexStartHeight_ + k * resolution_;
  Vector3 error = position - Vector3(xp, yp, zp);
  return data_[k](i, j) + gradient.dot(error);
}

Vector3 SignedDistanceField::getDistanceGradientAt(const Position3& position) const
{
  double xCenter = size_.x() / 2.0;
  double yCenter = size_.y() / 2.0;
  int i = std::round(xCenter - (position.x() - position_.x()) / resolution_);
  int j = std::round(yCenter - (position.y() - position_.y()) / resolution_);
  int k = std::round((position.z() - zIndexStartHeight_) / resolution_);
  i = std::max(i, 1);
  i = std::min(i, size_.x() - 2);
  j = std::max(j, 1);
  j = std::min(j, size_.y() - 2);
  k = std::max(k, 1);
  k = std::min(k, (int)data_.size() - 2);
  double dx = (data_[k](i - 1, j) - data_[k](i + 1, j)) / (2 * resolution_);
  double dy = (data_[k](i, j - 1) - data_[k](i, j + 1)) / (2 * resolution_);
  double dz = (data_[k + 1](i, j) - data_[k - 1](i, j)) / (2 * resolution_);
  return Vector3(dx, dy, dz);
}

void SignedDistanceField::convertToPointCloud(pcl::PointCloud<pcl::PointXYZI>& points) const
{
  double xCenter = size_.x() / 2.0;
  double yCenter = size_.y() / 2.0;
  for (size_t z = 0; z < data_.size(); z++){
    for (int y = 0; y < size_.y(); y++) {
      for (int x = 0; x < size_.x(); x++) {
        double xp = position_.x() + ((size_.x() - x) - xCenter) * resolution_;
        double yp = position_.y() + ((size_.y() - y) - yCenter) * resolution_;
        double zp = zIndexStartHeight_ + z * resolution_;
        pcl::PointXYZI p;
        p.x = xp;
        p.y = yp;
        p.z = zp;
        p.intensity = data_[z](x, y);
        points.push_back(p);
      }
    }
  }
  return;
}

} /* namespace */


text:
* Supports Composer
* Supports auto-wring
* Supports regexp-based interface-to-implementation mapping rules
* Supports interception
* Supports transient and singleton lifestyles
* Supports namespaces
* Supports scalar parameters
* Configurable through .INI file

## Scalar parameters
* configured as constructor parameter php variable name / value pair

## Limitations
* Only supports constructor depndency injection
* Pretty dumb config file
* Scalar parameter is a mess when multiple classes have same scalar variable name in their constructors

## Synopsys
```php
$dic = new Container(
		[ new IniBasedConfigurator("conf/DI-phpdic-conf.ini") ]
	);
$app = $dic->Resolve("\\app\\App01");
$app->Run();
```

## Composer package definition
Insert the following package definition into your composer.json
to install the piece of software with composer
```js
  "repositories": [
      {
        "type": "vcs",
        "url": "https://github.com/antimax/PHP-DependencyInjectionContainer.git"
      }
  ],
```

and refer to as
```js
  "require": {
      "antimax/PHP-DependencyInjectionContainer": "*"
  }
```

# PHP-DependencyInjectionContainer

PHP reflection-based dependency injection container with auto-wiring, auto-registration and interception support

## What is this?
This thing here is a result of an effort to implement a "mature" dependency injection container for PHP. This implementation supports all three must-have features wich a "mature" DI container must to support: object composition, object lifetime mamangement and interception.

[This excellent book](http://www.amazon.com/Dependency-Injection-NET-Mark-Seemann/dp/1935182501/) will give you comprehensive understanding of dependency injection ideology and dependency injection containers. Glossary of the book contains references to some other extremely valuable sources of information about SOLID object-oriented programming.

## Requirements
PHP 5.3.9 and above.

## Disadvantages
Since the container is reflection-based, it entirely relies on the type hinting in constructor declaration. That could be a problem for already existing projects being refactored, but I have strong opinion that for a newly created PHP code the type hinting should be a "must have" feature.

Since the container does all sanity checks for registrations, it requires all involved classes and interfaces to be declared prior the registration. This means that you should have "required_once" PHP files declaring classes and interfaces before registration phase. DI container package provides simple source code loader that addresses this issue.

## Advantages
Advantages of this implementation of DI container have the same roots as the disadvantages – it is reflection-based. As a result, we have:

* Instance registration
* Full auto-wiring support
* Automatic injection of a declared class instance
* Injection of a constructor scalar parameter
* Advanced injection of a constructor scalar parameter
* Auto-registration
* Singleton and transient lifestyle support
* Cyclic dependencies detection
* Full and out-of-the-box namespaces support
* Simple configuration
* Simple and laconic source code

## Interception
Read about instance interception [here](https://msdn.microsoft.com/en-us/library/ff660861(v=pandp.20).aspx#_Instance_Interception) and then take a look at [Stream.php](https://github.com/antimax/PHP-DependencyInjectionContainer/blob/master/Stream.php).

## Configurators and the .ini-based container configuration
See the sections [#9](#9-using-configurator-classes-to-initialize-container) and [#10](#10-ini-based-container-configuration) of this document.

## Examples
### 1. Instance registration and injection

```php
interface IA
{
}

interface IB
{
}

class A implements IA
{
	private $dependency = null;

	public function __construct(IB $dep)
	{
		$this->dependency = $dep;
	}
}

class  B implements IB
{
}

require_once 'DiContainer/Container.php';

$container = new DiContainer\Container();
$container->RegisterInstance('IB', new B());
$container->RegisterType('IA', 'A');

$instance = $container->Resolve('IA');
print_r($instance);
```

Here we have the interface `IA` and its implementation – the `A` class. The constructor of the class `A` has dependency on `IB`. The `B` class implements the interface `IB`.

`$container->RegisterInstance('IB', new B())` instructs the container to return a here instantiated instance of the class `B` every time the container is asked to resolve request for an instance of implementation of interface `IB`.

`$container->RegisterType('IA', 'A')` instructs the container to create an instance of class `A` every time the container is asked to resolve request for an instance of implementation of interface `IA`.

    A Object
    (
        [dependency:A:private] => B Object
            (
            )
    )

__*Note 1*__

You can do registrations in arbitrary mode. Therefore, this code works:

    $container->RegisterType('IA', 'A');
    $container->RegisterInstance('IB', new B());

__*Note 2*__

All registration calls (`registerInstance`, `RegisterType`, `RegisterTypeMappingRule`, `RegisterParameterValue`, `RegisterParameterCallback`) returns instance of the container. Therefore, registrations chaining works as well:

    $container->RegisterType('IA', 'A')->RegisterInstance('IB', new B());

__*Note 3*__

Container always returns the same instance which is originally registered by `$container->RegisterInstance(…)` call.

### 2. Full auto-wiring support

```php
require_once 'DiContainer/Container.php';

interface IA
{
}

interface IB
{
}

interface IC
{
}

interface ID
{
}

class A implements IA
{
	private $b = null;
	private $c = null;

	public function __construct(IB $b, IC $c)
	{
		$this->b = $b;
		$this->c = $c;
	}
}

class B implements IB
{
	private $d = null;

	function __construct(ID $d)
	{
		$this->d = $d;
	}
}

class C implements IC
{
}

class D implements ID
{
}

$container = new DiContainer\Container();
$container->RegisterType('IA', 'A')
	->RegisterType('IB', 'B')
	->RegisterType('IC', 'C')
	->RegisterType('ID', 'D');

$instance = $container->Resolve('IA');

print_r($instance);
```

Here we have the class `A` that implements the interface `IA`. The constructor of the class `A` depends on the interfaces `IB` and `IC`. The classes `B` and `C` implement the interfaces `IB` and `IC` respectively. The constructor of the class `B` depends on the interface `ID`.  We merely instruct the container which types implement the interfaces. The container does all the wiring automatically.

    A Object
    (
        [b:A:private] => B Object
            (
                [d:B:private] => D Object
                    (
                    )
            )

        [c:A:private] => C Object
            (
            )
    )

__*Note 1*__

You can use `$container-> RegisterTypeMappingRule(…)` to make configuration even simpler.

### 3. Namespaces and auto-registration

```php
    namespace Interfaces
    {
        interface IA
        {
        }

        interface IB
        {
        }

        interface IC
        {
        }

        interface ID
        {
        }
    }

    namespace Implementations
    {
        class A implements \Interfaces\IA
        {
            private $b = null;
            private $c = null;

            public function __construct(\Interfaces\IB $b, \Interfaces\IC $c)
            {
                $this->b = $b;
                $this->c = $c;
            }
        }

        class B implements \Interfaces\IB
        {
            private $d = null;

            function __construct(\Interfaces\ID $d)
            {
                $this->d = $d;
            }
        }

        class C implements \Interfaces\IC
        {
        }

        class D implements \Interfaces\ID
        {
        }
    }

    namespace
    {
        require_once 'DiContainer/Container.php';

        $container = new DiContainer\Container();
        $container->RegisterTypeMappingRule('~^Interfaces\\\I(.+)~', 'Implementations\\\${1}');
        $instance = $container->Resolve('Interfaces\IA');

        print_r($instance);
    }
```

Here we have a variant of the previous example that demonstrates the out-of-the-box namespaces support and the auto-registration feature. As you can see, every interface in the namespace `Interfaces` is implemented by a class in the namespace `Implementations`. You can also see that there is a direct dependency of implementation name on an interface name: Interfaces\I**Name** is implemented by Implementations\**Name**.

PHP provides us with the great function `preg_replace` that allows us to create a rule that generalizes this dependency. The only thing that `$container->RegisterTypeMappingRule(…)` actually does is that it iterates through all abstract types (interfaces and abstract classes) declared by the moment of the method call and uses the `preg_replace` function to try to construct a name of implementation class. If it has succeeded, `$container->RegisterType(…)` is called.

    Implementations\A Object
    (
        [b:Implementations\A:private] => Implementations\B Object
            (
                [d:Implementations\B:private] => Implementations\D Object
                    (
                    )

            )
        [c:Implementations\A:private] => Implementations\C Object
            (
            )
    )

__*Note 1*__

The first and the second parameters of the `RegisterTypeMappingRule` method are actually first and second parameters of the `preg_replace` function. The third parameter of the `preg_replace` function is an abstract type name.

__*Note 2*__

Namespaces in this example limit the scope of the rule to prevent it from being too generic.

### 4. Automatic injection of a declared class instance

```php
interface IA
{
}

class A implements IA
{
	private $b = null;

	public function __construct(B $b)
	{
		$this->b = $b;
	}
}

class B
{
	private $c = null;

	public function __construct(C $c)
	{
		$this->c = $c;
	}
}

class  C
{
}

require_once 'DiContainer/Container.php';

$container = new DiContainer\Container();
$container->RegisterType('IA', 'A');
$instance = $container->Resolve('IA');

print_r($instance);
```

Here we have the class `A` that implements the interface `IA`. The constructor of the class `A` depends on an instance of the non-abstract class `B`. The constructor of the class `B`, in turn, depends on the instance of some other non-abstract class `C`. In this case, the container creates instances of class `B` and class `C` without any additional instructions. Auto-wiring works as well.

    A Object
    (
        [b:A:private] => B Object
            (
                [c:B:private] => C Object
                    (
                    )
            )
    )

__*Note 1*__

Unfortunately, by this moment the latest stable version of PHP (5.4.12) does not allow Reflection API to work with built-in classes. This means you cannot use, for instance, `Exception` in place of, say, `B` in this example.

__*Note 2*__

If a constructor has dependency on an interface or a class (not on a scalar), auto-wiring will try to create instance even if this parameter has default value `null` specified.

### 5. Injection of a constructor scalar parameter

```php
interface IA
{
}

class A implements IA
{
	private $scalar = null;

	public function __construct($scalar)
	{
		$this->scalar = $scalar;
	}
}

class  TopDependency
{
}

require_once 'DiContainer/Container.php';

$container = new DiContainer\Container();
$container->RegisterType('IA', 'A')->RegisterParameterValue('scalar', 'this is scalar value');
$instance = $container->Resolve('IA');

print_r($instance);
```

Here we have the class `A` that implements the interface `IA`. The class `A` constructor depends on the scalar `$scalar`. We can easily instruct the container how to handle that.

    A Object
    (
        [scalar:A:private] => this is scalar value
    )

__*Note 1*__

If a constructor scalar parameter has a default value specified, then it is used in the case when this scalar parameter is not registered with the container.

### 6. Advanced injection of a constructor scalar parameter

```php
require_once 'DiContainer/Container.php';

interface IA
{
}

interface IB
{
}

class A implements IA
{
	private $b = null;
	private $scalar = null;

	public function __construct(IB $b, $scalar)
	{
		$this->b = $b;
		$this->scalar = $scalar;
	}
}

class B implements IB
{
	private $scalar = null;

	function __construct($scalar)
	{
		$this->scalar = $scalar;
	}
}

$container = new DiContainer\Container();
$container->RegisterType('IA', 'A')
	->RegisterType('IB', 'B')
	->RegisterParameterCallback('scalar', function (ReflectionClass $reflectionClass) {
		return "The scalar value for an instance of the class {$reflectionClass->getName()}";

	});

$instance = $container->Resolve('IA');

print_r($instance);
```

Here we have the interfaces `IA` and `IB` and their implementations. Both implementations depend on the scalar parameter `$scalar`. We want this scalar parameter to have a different value for different implementations. `$container->RegisterParameterCallback(…)` allows us to defined a call-back function that gets information about the class being instantiated as a parameter of the `ReflectionClass` type.

    A Object
    (
        [b:A:private] => B Object
            (
                [scalar:B:private] => The scalar value for an instance of the class B
            )
        [scalar:A:private] => The scalar value for an instance of the class A
    )

__*Note 1*__

`$container->RegisterParameterValue(…)` actually creates a closure and then calls `$container->RegisterParameterCallback(…)`.

### 7. Singleton lifestyle support

```php

require_once 'DiContainer/Container.php';

interface IA
{
}

interface IB
{
}

interface IC
{
}

interface ID
{
}

class A implements IA
{
	public $b = null;
	public $c = null;

	public function __construct(IB $b, IC $c)
	{
		$this->b = $b;
		$this->c = $c;
	}
}

class B implements IB
{
	public $d = null;

	public function __construct(ID $d)
	{
		$this->d = $d;
	}
}

class C implements IC
{
	public $d = null;

	public function __construct(ID $d)
	{
		$this->d = $d;
	}
}

class D implements ID
{
}

$container = new DiContainer\Container();
$container->RegisterType('IA', 'A')
	->RegisterType('IB', 'B')
	->RegisterType('IC', 'C')
	->RegisterType('ID', 'D', true);

$instance = $container->Resolve('IA');
print_r($instance);
print $instance->b->d === $instance->c->d ? 'TRUE' : 'FALSE';
```

Here we have four interfaces: `IA`, `IB`, `IC` and `ID`. The Class `A` that implements the interface `IA` has dependency on `IB` and `IC`. The classes `B` and `C` that implement the interfaces `IB` and `IC` respectively have dependency on the interface `ID`. The class `D` that implements the interface `ID` does not have dependencies. The class `D` is registered as implementation of the `ID` interface with singleton lifestyle flag set therefore just one instance of the class `D` is created and the result of `$instance->b->d === $instance->c->d ? 'TRUE' : 'FALSE';` is `'TRUE'`.

    A Object
    (
        [b] => B Object
            (
                [d] => D Object
                    (
                    )

            )

        [c] => C Object
            (
                [d] => D Object
                    (
                    )

            )

    )
    TRUE

__*Note 1*__

Transient is the default lifestyle.

### 8. Cyclic dependencies detection

```php
require_once 'DiContainer/Container.php';

interface IA
{
}

interface IB
{
}

interface IC
{
}

interface ID
{
}

class A implements IA
{
	public $b = null;

	public function __construct(IB $b)
	{
		$this->b = $b;
	}
}

class B implements IB
{
	public $c = null;

	public function __construct(IC $c)
	{
		$this->c = $c;
	}
}

class C implements IC
{
	public $d = null;

	public function __construct(ID $d)
	{
		$this->d = $d;
	}
}

class D implements ID
{
	public $a = null;

	public function __construct(IA $a)
	{
		$this->a = $a;
	}
}

$container = new DiContainer\Container();
$container->RegisterType('IA', 'A')
	->RegisterType('IB', 'B')
	->RegisterType('IC', 'C')
	->RegisterType('ID', 'D');

$instance = $container->Resolve('IA');
```

Here we have four interfaces `IA`, `IB`, `IC` and `ID` and their implementations – classes `A`, `B`, `C` and `D`. `A` depends on `IB`, `B` depends on `IC`, `C` depends on `ID` and `D` depends on `IA`, thus we have the dependencies cycle. The container detects this situation and throws exception rather than to stuck in an infinite loop.

    PHP Fatal error:  Uncaught exception 'InvalidArgumentException' with message 'Cyclic dependency on the type 'IA' detected' in /home/max/projects/container/DiContainer/Container.php:207
    Stack trace:
    #0 /container/DiContainer/Container.php(235): DiContainer\Container->RecursiveResolve('IA', Array)
    #1 /container/DiContainer/Container.php(235): DiContainer\Container->RecursiveResolve('ID', Array)
    #2 /container/DiContainer/Container.php(235): DiContainer\Container->RecursiveResolve('IC', Array)
    #3 /container/DiContainer/Container.php(235): DiContainer\Container->RecursiveResolve('IB', Array)
    #4 /container/DiContainer/Container.php(169): DiContainer\Container->RecursiveResolve('IA', Array)
    #5 /container/example8.php(68): DiContainer\Container->Resolve('IA')
    #6 {main}
      thrown in /container/DiContainer/Container.php on line 207

### 9. Using configurator classes to initialize container

```php
require_once 'DiContainer/Container.php';

interface IA
{
}

interface IB
{
}

interface IC
{
}

interface ID
{
}

class A implements IA
{
	private $b = null;
	private $c = null;

	public function __construct(IB $b, IC $c)
	{
		$this->b = $b;
		$this->c = $c;
	}
}

class B implements IB
{
	private $d = null;

	function __construct(ID $d)
	{
		$this->d = $d;
	}
}

class C implements IC
{
}

class D implements ID
{
}

class Configurator1 implements DiContainer\IConfigurator
{
	public function Configure(DiContainer\Container $container)
	{
		$container->RegisterType('IA', 'A')
			->RegisterType('IB', 'B')
			->RegisterType('IC', 'C');
	}
}

class Configurator2 implements DiContainer\IConfigurator
{
	public function Configure(DiContainer\Container $container)
	{
		$container->RegisterType('ID', 'D');
	}
}

$container = new DiContainer\Container(array(new Configurator1(), new Configurator2()));
$instance = $container->Resolve('IA');

print_r($instance);
```

If for some reason, you want to delegate container initialization logic to one or multiple classes you can easily do it. The first parameter of the container constructor is an array of objects implementing `DiContainer\IConfigurator` interface.

```php
interface IConfigurator
{
	function Configure(Container $container);
}
```

This example is essentially slightly modified example #2 with the only difference that initialization logic was moved into two classes `Configurator1` and `Configurator2` both implementing the `DiContainer\IConfigurator` interface. The result of the code execution is exactly the same.

    A Object
    (
        [b:A:private] => B Object
            (
                [d:B:private] => D Object
                    (
                    )

            )

        [c:A:private] => C Object
            (
            )
    )

__*Note 1*__

The default value of the first parameter is `null`.

__*Note 2*__

The same instance of the container is passed in turn into every particular configurator starting from the first one.

### 10. INI based container configuration

```php
namespace Interfaces
{
    interface IA
    {
    }
}

namespace Implementations
{
    class A implements \Interfaces\IA
    {
    }
}

namespace
{
    require_once 'DiContainer/Container.php';
    require_once 'DiContainer/IniBasedConfigurator.php';

    interface IA
    {
    }

    interface IB
    {
    }

    class A implements IA
    {
        private $foo;

        function __construct($foo)
        {
            $this->foo = $foo;
        }
    }

    class B implements IB
    {
        private $bar;

        function __construct($bar)
        {
            $this->bar = $bar;
        }
    }

    $container = new DiContainer\Container(array(new DiContainer\IniBasedConfigurator('container.ini')));
    print_r($container->Resolve('Interfaces\IA'));
    print_r($container->Resolve('IA'));
    print_r($container->Resolve('IB'));
}
```

Output

    Implementations\A Object
    (
    )
    A Object
    (
        [foo:A:private] => foo_value
    )
    B Object
    (
        [bar:B:private] => bar_value
    )

The `DiContainer` namespace contains the class `DiContainer\IniBasedConfigurator` that provides implementation of the `DiContainer\IConfigurator` interface that can read container configuration from the standard [PHP INI file](http://php.net/manual/en/function.parse-ini-file.php). `$container = new DiContainer\Container(array(new DiContainer\IniBasedConfigurator('container.ini')));` creates instance of the container that is being initialized by the instance of the `DiContainer\IniBasedConfigurator` which reads configuration from the `container.ini`.

    [type_rule_mapping]
    abstract_type_name_pattern[] = ~^Interfaces\\I(.+)$~
    implementation_type_name_replacement[] = Implementations\\${1}

    [type_mapping]
    abstract_type[] = IA
    implementation_type[] = A
    abstract_type[] = IB
    implementation_type[] = B

    [parameter_value_mapping]
    parameter[] = foo
    value[] = foo_value
    parameter[] = bar
    value[] = bar_value

This is an equivalent of the following code execution

    $container->RegisterTypeMappingRule('~^Interfaces\\\I(.+)~', 'Implementations\\\${1}')
            ->RegisterType('IA', 'A')->RegisterType('IB', 'B')
            ->RegisterParameterValue('foo', 'foo_value')
            ->RegisterParameterValue('bar', 'bar_value');

__*Note 1*__

Here you can see another example of the out-of-the-box namespaces support. The container distinguishes two abstract types declared in different namespaces (IA and Interfaces\IA).