text:
package org.keycloak.models.sessions.infinispan;

import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.sessions.infinispan.changes.InfinispanChangelogBasedTransaction;
import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshChecker;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.changes.Tasks;
import org.keycloak.models.sessions.infinispan.changes.UserSessionUpdateTask;
import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshListener;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;

import static org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshListener.IGNORE_REMOTE_CACHE_UPDATE;

/**
 * @author Stian Thorgersen
 */
public class UserSessionAdapter implements UserSessionModel {

    private final KeycloakSession session;

    private final InfinispanUserSessionProvider provider;

    private final InfinispanChangelogBasedTransaction<String, UserSessionEntity> userSessionUpdateTx;

    private final InfinispanChangelogBasedTransaction<UUID, AuthenticatedClientSessionEntity> clientSessionUpdateTx;

    private final RealmModel realm;

    private final UserSessionEntity entity;

    private final boolean offline;

    private SessionPersistenceState persistenceState;

    public UserSessionAdapter(KeycloakSession session, InfinispanUserSessionProvider provider,
                              InfinispanChangelogBasedTransaction<String, UserSessionEntity> userSessionUpdateTx,
                              InfinispanChangelogBasedTransaction<UUID, AuthenticatedClientSessionEntity> clientSessionUpdateTx,
                              RealmModel realm, UserSessionEntity entity, boolean offline) {
        this.session = session;
        this.provider = provider;
        this.userSessionUpdateTx = userSessionUpdateTx;
        this.clientSessionUpdateTx = clientSessionUpdateTx;
        this.realm = realm;
        this.entity = entity;
        this.offline = offline;
    }

    @Override
    public Map<String, AuthenticatedClientSessionModel> getAuthenticatedClientSessions() {
        AuthenticatedClientSessionStore clientSessionEntities = entity.getAuthenticatedClientSessions();
        Map<String, AuthenticatedClientSessionModel> result = new HashMap<>();

        List<String> removedClientUUIDS = new LinkedList<>();

        if (clientSessionEntities != null) {
            clientSessionEntities.forEach((String key, UUID value) -> {
                // Check if client still exists
                ClientModel client = realm.getClientById(key);
                if (client != null) {
                    final AuthenticatedClientSessionAdapter clientSession = provider.getClientSession(this, client, value, offline);
                    if (clientSession != null) {
                        result.put(key, clientSession);
                    }
                } else {
                    removedClientUUIDS.add(key);
                }
            });
        }

        removeAuthenticatedClientSessions(removedClientUUIDS);

        return Collections.unmodifiableMap(result);
    }

    @Override
    public AuthenticatedClientSessionModel getAuthenticatedClientSessionByClient(String clientUUID) {
        AuthenticatedClientSessionStore clientSessionEntities = entity.getAuthenticatedClientSessions();
        final UUID clientSessionId = clientSessionEntities.get(clientUUID);

        if (clientSessionId == null) {
            return null;
        }

        ClientModel client = realm.getClientById(clientUUID);

        if (client != null) {
            return provider.getClientSession(this, client, clientSessionId, offline);
        }

        removeAuthenticatedClientSessions(Collections.singleton(clientUUID));
        return null;
    }

    private static final int MINIMUM_INACTIVE_CLIENT_SESSIONS_TO_CLEANUP = 5;

    @Override
    public void removeAuthenticatedClientSessions(Collection<String> removedClientUUIDS) {
        if (removedClientUUIDS == null || removedClientUUIDS.isEmpty()) {
            return;
        }

        // Performance: do not remove the clientUUIDs from the user session until there is enough of them;
        // an invalid session is handled as nonexistent in UserSessionAdapter.getAuthenticatedClientSessions()
        if (removedClientUUIDS.size() >= MINIMUM_INACTIVE_CLIENT_SESSIONS_TO_CLEANUP) {
            // Update user session
            UserSessionUpdateTask task = new UserSessionUpdateTask() {
                @Override
                public void runUpdate(UserSessionEntity entity) {
                    removedClientUUIDS.forEach(entity.getAuthenticatedClientSessions()::remove);
                }
            };
            update(task);
        }

        // do not iterate the removedClientUUIDS and remove the clientSession directly as the addTask can manipulate
        // the collection being iterated, and that can lead to unpredictable behaviour (e.g. NPE)
        List<UUID> clientSessionUuids = removedClientUUIDS.stream()
          .map(entity.getAuthenticatedClientSessions()::get)
          .filter(Objects::nonNull)
          .collect(Collectors.toList());

        clientSessionUuids.forEach(clientSessionId -> this.clientSessionUpdateTx.addTask(clientSessionId, Tasks.removeSync()));
    }

    public String getId() {
        return entity.getId();
    }

    @Override
    public RealmModel getRealm() {
        return realm;
    }

    @Override
    public String getBrokerSessionId() {
        return entity.getBrokerSessionId();
    }

    @Override
    public String getBrokerUserId() {
        return entity.getBrokerUserId();
    }
    public UserModel getUser() {
        return session.users().getUserById(realm, entity.getUser());
    }

    @Override
    public String getLoginUsername() {
        if (entity.getLoginUsername() == null) {
            // this is a hack so that UserModel doesn't have to be available when offline token is imported.
            // see related JIRA - KEYCLOAK-5350 and corresponding test
            return getUser().getUsername();
        } else {
            return entity.getLoginUsername();
        }
    }

    public String getIpAddress() {
        return entity.getIpAddress();
    }

    @Override
    public String getAuthMethod() {
        return entity.getAuthMethod();
    }

    @Override
    public boolean isRememberMe() {
        return entity.isRememberMe();
    }

    public int getStarted() {
        return entity.getStarted();
    }

    public int getLastSessionRefresh() {
        return entity.getLastSessionRefresh();
    }

    public void setLastSessionRefresh(int lastSessionRefresh) {
        if (offline) {
            // Received the message from the other DC that we should update the lastSessionRefresh in local cluster. Don't update DB in that case.
            // The other DC already did.
            Boolean ignoreRemoteCacheUpdate = (Boolean) session.getAttribute(CrossDCLastSessionRefreshListener.IGNORE_REMOTE_CACHE_UPDATE);
            if (ignoreRemoteCacheUpdate == null || !ignoreRemoteCacheUpdate) {
                provider.getPersisterLastSessionRefreshStore().putLastSessionRefresh(session, entity.getId(), realm.getId(), lastSessionRefresh);
            }
        }

        UserSessionUpdateTask task = new UserSessionUpdateTask() {

            @Override
            public void runUpdate(UserSessionEntity entity) {
                entity.setLastSessionRefresh(lastSessionRefresh);
            }

            @Override
            public CrossDCMessageStatus getCrossDCMessageStatus(SessionEntityWrapper<UserSessionEntity> sessionWrapper) {
                return new CrossDCLastSessionRefreshChecker(provider.getLastSessionRefreshStore(), provider.getOfflineLastSessionRefreshStore())
                        .shouldSaveUserSessionToRemoteCache(UserSessionAdapter.this.session, UserSessionAdapter.this.realm, sessionWrapper, offline, lastSessionRefresh);
            }

            @Override
            public String toString() {
                return "setLastSessionRefresh(" + lastSessionRefresh + ')';
            }
        };

        update(task);
    }

    @Override
    public boolean isOffline() {
        return offline;
    }

    @Override
    public String getNote(String name) {
        return entity.getNotes() != null ? entity.getNotes().get(name) : null;
    }

    @Override
    public void setNote(String name, String value) {
        UserSessionUpdateTask task = new UserSessionUpdateTask() {

            @Override
            public void runUpdate(UserSessionEntity entity) {
                if (value == null) {
                    if (entity.getNotes().containsKey(name)) {
                        removeNote(name);
                    }
                    return;
                }
                entity.getNotes().put(name, value);
            }

        };

        update(task);
    }

    @Override
    public void removeNote(String name) {
        UserSessionUpdateTask task = new UserSessionUpdateTask() {

            @Override
            public void runUpdate(UserSessionEntity entity) {
                entity.getNotes().remove(name);
            }

        };

        update(task);
    }

    @Override
    public Map<String, String> getNotes() {
        return entity.getNotes();
    }

    @Override
    public State getState() {
        return entity.getState();
    }

    @Override
    public void setState(State state) {
        UserSessionUpdateTask task = new UserSessionUpdateTask() {

            @Override
            public void runUpdate(UserSessionEntity entity) {
                entity.setState(state);
            }

        };

        update(task);
    }

    public SessionPersistenceState getPersistenceState() {
        return persistenceState;
    }

    public void setPersistenceState(SessionPersistenceState persistenceState) {
        this.persistenceState = persistenceState;
    }

    @Override
    public void restartSession(RealmModel realm, UserModel user, String loginUsername, String ipAddress, String authMethod, boolean rememberMe, String brokerSessionId, String brokerUserId) {
        UserSessionUpdateTask task = new UserSessionUpdateTask() {

            @Override
            public void runUpdate(UserSessionEntity entity) {
                provider.updateSessionEntity(entity, realm, user, loginUsername, ipAddress, authMethod, rememberMe, brokerSessionId, brokerUserId);

                entity.setState(null);
                entity.getNotes().clear();
                entity.getAuthenticatedClientSessions().clear();
            }

        };

        update(task);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || !(o instanceof UserSessionModel)) return false;

        UserSessionModel that = (UserSessionModel) o;
        return that.getId().equals(getId());
    }

    @Override
    public int hashCode() {
        return getId().hashCode();
    }

    UserSessionEntity getEntity() {
        return entity;
    }

    void update(UserSessionUpdateTask task) {
        userSessionUpdateTx.addTask(getId(), task);
    }

}


text:
/* jshint -W097 */
'use strict';

/* jshint -W117 */
var path = require('path');
var fs = require("fs");

/* jshint -W117 */
module.exports = function () {
    var utils = {};

    utils.GetRevFileName = function (productionFolder) {
        // Get the production filename from the rev-manifest.json file
        //console.log("Looking for file: \n" + productionFolder + "rev-manifest.json");
        var revFile = fs.readFileSync(productionFolder + "rev-manifest.json");
        //console.log("Got contents: \n" + revFile);
        var rev = JSON.parse(revFile);

        var first;
        for (var i in rev) {
            if (rev.hasOwnProperty(i) && typeof (i) !== 'function') {
                first = rev[i];
                break;
            }
        }

        //console.log("Got file: \n", first);

        return productionFolder + first;
    };

    utils.AppBuilder = function (logger, name) {
        this.logger = logger;
        this.name = name;
        this.htmlDestination = null;

        this.angular = {
            folder: null,
            hasSpecs: false,
            hasThirdParty: false
        };

        this.js = {
            folder: null,
            hasThirdParty: false
        };

        this.less = {
            folder: null
        };

        this.setHtmlDestination = function (file) {
            this.htmlDestination = file;
            return this;
        };

        this.addAngularJs = function (folder) {
            this.angular.folder = folder;
            return this;
        };

        this.hasAngularSpecs = function () {
            this.angular.hasSpecs = true;
            return this;
        };

        this.hasAngularThirdPartyJs = function () {
            this.angular.hasThirdParty = true;
            return this;
        };

        this.addJs = function (folder) {
            this.js.folder = folder;
            return this;
        };

        this.hasThirdPartyJs = function () {
            this.js.hasThirdParty = true;
            return this;
        };

        this.addLess = function (folder) {
            this.less.folder = folder;
            return this;
        };

        this.build = function () {
            var config = {
                name: this.name,
                hasAngular: false,
                hasJs: false,
                hasLess: false
            };

            if (this.htmlDestination !== null) {
                config.htmlDestination = this.htmlDestination;
            }

            if (this.angular.folder !== null) {
                config.hasAngular = true;
                config.angular = {
                    folder: this.angular.folder,
                    files: [
                        this.angular.folder + 'app.js',
                        this.angular.folder + '*.controller.js',
                        this.angular.folder + '*.directive.js',
                        this.angular.folder + '*.filter.js',
                        this.angular.folder + '*.service.js'
                    ],
                    development: {
                        htmlInjection: {
                            tagName: this.name + 'Development',
                        },
                    },
                    production: {
                        folder: this.angular.folder + 'production/',
                        bundleName: this.name + '.js',
                        htmlInjection: {
                            tagName: this.name + 'Production',
                        }
                    }
                };

                config.angular.hasSpecs = false;
                if (this.angular.hasSpecs) {
                    config.angular.hasSpecs = true;
                    config.angular.specs = this.angular.folder + '*.spec.js';
                }

                config.angular.hasThirdParty = false;
                if (this.angular.hasThirdParty) {
                    config.angular.hasThirdParty = true;
                }
            }

            if (this.js.folder !== null) {
                config.hasJs = true;
                config.js = {
                    folder: this.js.folder,
                    files: this.js.folder + '*.js',
                    development: {
                        htmlInjection: {
                            tagName: this.name + 'Development',
                        },
                    },
                    production: {
                        folder: this.js.folder + 'production/',
                        bundleName: this.name + '.js',
                        htmlInjection: {
                            tagName: this.name + 'Production',
                        }
                    }
                };

                config.js.hasThirdParty = false;
                if (this.js.hasThirdParty) {
                    config.js.hasThirdParty = true;
                }
            }

            if (this.less.folder !== null) {
                config.hasLess = true;
                config.less = {
                    folder: this.less.folder,
                    development: {
                        htmlInjection: {
                            tagName: this.name + 'Development',
                        },
                    },
                    production: {
                        folder: this.less.folder + 'production/',
                        bundleName: this.name + '.css',
                        htmlInjection: {
                            tagName: this.name + 'Production',
                        }
                    }
                };
            }

            return config;
        };
    };

    utils.SuiteBuilder = function (logger, apps) {
        this.logger = logger;
        this.apps = apps;

        this.BuildLessToCompile = function () {
            return this.apps.filter(function (app) {
                return app.hasLess;
            }).map(function (app) {
                return {
                    src: app.less.folder + '*.less',
                    dest: app.less.folder,
                };
            });
        };

        this.BuildLessToWatch = function () {
            return this.BuildLessToCompile().map(function (less) {
                return less.src;
            });
        };

        this.BuildLessToValidate = function () {
            return this.apps.filter(function (app) {
                return app.hasLess;
            }).map(function (app) {
                return {
                    src: app.less.folder + '*.less',
                    dest: app.less.folder,
                };
            });
        };

        this.BuildCssToAutoPrefix = function () {
            return this.apps.filter(function (app) {
                return app.hasLess;
            }).map(function (app) {
                return {
                    src: app.less.folder + '*.css',
                    dest: app.less.folder,
                };
            });
        };

        this.BuildCssToInject = function () {
            var results = [];
            this.apps.forEach(function (app) {
                if (app.hasLess) {
                    if (results.filter(function (result) { return result.src === app.htmlDestination; }).length === 0) {
                        results.push({
                            src: app.htmlDestination,
                            dest: path.dirname(app.htmlDestination),
                            tags: [],
                        });
                    }

                    var tags = results.filter(function (result) {
                        return result.src === app.htmlDestination;
                    })[0].tags;

                    if (tags.filter(function (tag) {
                        return tag.tagName == app.less.development.htmlInjection.tagName;
                    })) {
                        tags.push({
                            ignorePath: '/wwwroot',
                            tagName: app.less.development.htmlInjection.tagName,
                            css: [],
                        });
                    }

                    var css = tags.filter(function (tag) {
                        return tag.tagName == app.less.development.htmlInjection.tagName;
                    })[0].css;
                    css.push(app.less.folder + '*.css');
                }
            });

            return results;
        };

        this.BuildCssToBundle = function () {
            return this.apps.filter(function (app) {
                return app.hasLess;
            }).map(function (app) {
                return {
                    src: app.less.folder + '*.css',
                    dest: app.less.production.folder,
                    bundleName: app.less.production.bundleName,
                };
            });
        };

        this.BuildCssToDeploy = function () {
            var results = [];
            this.apps.forEach(function (app) {
                if (app.hasLess) {
                    if (results.filter(function (result) { return result.src === app.htmlDestination; }).length === 0) {
                        results.push({
                            src: app.htmlDestination,
                            dest: path.dirname(app.htmlDestination),
                            tags: [],
                        });
                    }

                    var tags = results.filter(function (result) {
                        return result.src === app.htmlDestination;
                    })[0].tags;

                    if (tags.filter(function (tag) {
                        return tag.tagName == app.less.production.htmlInjection.tagName;
                    })) {
                        var cssObj = {
                            ignorePath: '/wwwroot',
                            tagName: app.less.production.htmlInjection.tagName,
                            internalCss: [],
                        };
                        Object.defineProperty(cssObj, 'css', {
                            get: function () {
                                return cssObj.internalCss.map(function (folder) {
                                    return utils.GetRevFileName(folder);
                                });
                            }
                        });
                        tags.push(cssObj);
                    }

                    var css = tags.filter(function (tag) {
                        return tag.tagName == app.less.production.htmlInjection.tagName;
                    })[0].internalCss;
                    css.push(app.less.production.folder);
                }
            });

            return results;
        };

        this.BuildJsToValidate = function () {
            return [].concat(
                    this.apps.filter(function (app) {
                        return app.hasJs;
                    }).map(function (app) {
                        return {
                            src: app.js.files,
                            dest: app.js.folder,
                        };
                    }),
                    this.apps.filter(function (app) {
                        return app.hasAngular;
                    }).map(function (app) {
                        return {
                            src: app.angular.files,
                            dest: app.angular.folder,
                        };
                    }),
                    this.apps.filter(function (app) {
                        return app.hasAngular && app.angular.hasSpecs;
                    }).map(function (app) {
                        return {
                            src: app.angular.specs,
                            dest: app.angular.folder,
                        };
                    })
            );
        };

        this.BuildJsToInject = function () {
            var results = [];
            this.apps.forEach(function (app) {
                if (app.hasJs || app.hasAngular) {
                    if (results.filter(function (result) { return result.src === app.htmlDestination; }).length === 0) {
                        results.push({
                            src: app.htmlDestination,
                            dest: path.dirname(app.htmlDestination),
                            tags: [],
                        });
                    }

                    var tags = results.filter(function (result) {
                        return result.src === app.htmlDestination;
                    })[0].tags;

                    if (app.hasJs) {
                        if (tags.filter(function (tag) {
                            return tag.tagName == app.js.development.htmlInjection.tagName;
                        }).length === 0) {
                            tags.push({
                                ignorePath: '/wwwroot',
                                tagName: app.js.development.htmlInjection.tagName,
                                js: [],
                            });
                        }

                        var js = tags.filter(function (tag) {
                            return tag.tagName == app.js.development.htmlInjection.tagName;
                        })[0].js;
                        if (app.js.hasThirdParty) {
                            js.push(app.js.folder + '3rdParty/*.js');
                        }
                        js.push(app.js.files);
                    }
                    if (app.hasAngular) {
                        if (tags.filter(function (tag) {
                            return tag.tagName == app.angular.development.htmlInjection.tagName;
                        }).length === 0) {
                            tags.push({
                                ignorePath: '/wwwroot',
                                tagName: app.angular.development.htmlInjection.tagName,
                                js: [],
                            });
                        }

                        var angular = tags.filter(function (tag) {
                            return tag.tagName == app.angular.development.htmlInjection.tagName;
                        })[0].js;
                        if (app.angular.hasThirdParty) {
                            angular.push(app.angular.folder + '3rdParty/*.js');
                        }
                        Array.prototype.push.apply(angular, app.angular.files);
                    }
                }
            });

            return results;
        };

        this.BuildJsToBundle = function () {
            return [].concat(
                this.apps.filter(function (app) {
                    return app.hasJs;
                }).map(function (app) {
                    return {
                        src: [
                            app.js.folder + '3rdParty/*.js',
                            app.js.files,
                        ],
                        dest: app.js.production.folder,
                        bundleName: app.js.production.bundleName,
                    };
                }),
                this.apps.filter(function (app) {
                    return app.hasAngular;
                }).map(function (app) {
                    var src = [];
                    if (app.angular.hasSpecs) {
                        src.push(app.angular.folder + '3rdParty/*.js');
                    }

                    Array.prototype.push.apply(src, app.angular.files);
                    return {
                        src: src,
                        dest: app.angular.production.folder,
                        bundleName: app.angular.production.bundleName,
                    };
                })
            );
        };

        this.BuildJsToDeploy = function () {
            var results = [];
            this.apps.forEach(function (app) {
                if (app.hasJs || app.hasAngular) {
                    if (results.filter(function (result) { return result.src === app.htmlDestination; }).length === 0) {
                        results.push({
                            src: app.htmlDestination,
                            dest: path.dirname(app.htmlDestination),
                            tags: [],
                        });
                    }

                    var tags = results.filter(function (result) {
                        return result.src === app.htmlDestination;
                    })[0].tags;

                    if (app.hasJs) {
                        if (tags.filter(function (tag) {
                            return tag.tagName == app.js.production.htmlInjection.tagName;
                        })) {
                            /*
                            var foo = { bar: 123 };
                            Object.defineProperty(foo, 'bar', {
                                get: function () { return bar; },
                                set: function (value) { this.bar = value; }
                            });
                            console.log(foo.bar);
                            foo.bar = 456;
                            console.log(foo.bar);
                            */

                            var jsObj = {
                                ignorePath: '/wwwroot',
                                tagName: app.js.production.htmlInjection.tagName,
                                internalJs: []
                            };
                            Object.defineProperty(jsObj, 'js', {
                                get: function() {
                                    return jsObj.internalJs.map(function (folder) {
                                        return utils.GetRevFileName(folder);
                                    });
                                }
                            });
                            tags.push(jsObj);
                        }

                        var js = tags.filter(function (tag) {
                            return tag.tagName == app.js.production.htmlInjection.tagName;
                        })[0].internalJs;

                        js.push(app.js.production.folder);
                    }

                    if (app.hasAngular) {
                        if (tags.filter(function (tag) {
                            return tag.tagName == app.angular.production.htmlInjection.tagName;
                        })) {
                            var jsObj = {
                                ignorePath: '/wwwroot',
                                tagName: app.angular.production.htmlInjection.tagName,
                                internalJs: [],
                            };
                            Object.defineProperty(jsObj, 'js', {
                                get: function () {
                                    return jsObj.internalJs.map(function (folder) {
                                        return utils.GetRevFileName(folder);
                                    });
                                }
                            });
                            tags.push(jsObj);
                        }

                        var angular = tags.filter(function (tag) {
                            return tag.tagName == app.angular.production.htmlInjection.tagName;
                        })[0].internalJs;

                        angular.push(app.angular.production.folder);
                    }

                }
            });

            return results;
        };

        this.BuildJsToWatch = function () {
            return this.BuildJsToValidate().map(function (js) {
                return js.src;
            });
        };

        this.BuildSpecsToBuild = function () {
            return this.apps.filter(function (app) {
                return app.hasAngular;
            }).map(function (app) {
                return {
                    src: app.angular.files,
                    testlibraries: [
                        'node_modules/mocha/mocha.js',
                        'node_modules/chai/chai.js',
                        'node_modules/mocha-clean/index.js',
                        'node_modules/sinon-chai/lib/sinon-chai.js'
                    ],
                    specs: app.angular.specs,
                    name: app.name
                };
            });
        };
    };

    return utils;
};

redpajama_set_name: RedPajamaGithub


text:
AFNetworking-DeliveryGuarantee
==============================

An `AFNetworking` category that guarantees delivery using Background Completion Task (which added on iOS6), Background Transfer Service (which added on iOS7), Background Fetch (iOS7) with appropriate fallbacks.

It queues request operations and try to request until it returns successive http status code.

References
---

- ios - Long-Running Upload Task In Background - Stack Overflow : http://stackoverflow.com/questions/20576302/long-running-upload-task-in-background
- Multitasking in iOS 7 - iOS 7 - objc.io issue #5 : http://www.objc.io/issue-5/multitasking.html
- アプリのバックグラウンド処理 | iOS 7エンジニア勉強会 : http://www.slideshare.net/techblogyahoo/3-ios7-workshopmultitask-26997115


text:
#define DT_DRV_COMPAT st_iis3dhhc

#include <zephyr/kernel.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>

#include "iis3dhhc.h"

LOG_MODULE_DECLARE(IIS3DHHC, CONFIG_SENSOR_LOG_LEVEL);

/**
 * iis3dhhc_enable_int - enable selected int pin to generate interrupt
 */
static int iis3dhhc_enable_int(const struct device *dev, int enable)
{
	struct iis3dhhc_data *iis3dhhc = dev->data;

	/* set interrupt */
#ifdef CONFIG_IIS3DHHC_DRDY_INT1
	return iis3dhhc_drdy_on_int1_set(iis3dhhc->ctx, enable);
#else
	return iis3dhhc_drdy_on_int2_set(iis3dhhc->ctx, enable);
#endif
}

/**
 * iis3dhhc_trigger_set - link external trigger to event data ready
 */
int iis3dhhc_trigger_set(const struct device *dev,
			 const struct sensor_trigger *trig,
			 sensor_trigger_handler_t handler)
{
	struct iis3dhhc_data *iis3dhhc = dev->data;
	const struct iis3dhhc_config *config = dev->config;
	int16_t raw[3];

	if (!config->int_gpio.port) {
		return -ENOTSUP;
	}

	if (trig->chan == SENSOR_CHAN_ACCEL_XYZ) {
		iis3dhhc->handler_drdy = handler;
		if (handler) {
			/* dummy read: re-trigger interrupt */
			iis3dhhc_acceleration_raw_get(iis3dhhc->ctx, raw);
			return iis3dhhc_enable_int(dev, PROPERTY_ENABLE);
		} else {
			return iis3dhhc_enable_int(dev, PROPERTY_DISABLE);
		}
	}

	return -ENOTSUP;
}

/**
 * iis3dhhc_handle_interrupt - handle the drdy event
 * read data and call handler if registered any
 */
static void iis3dhhc_handle_interrupt(const struct device *dev)
{
	struct iis3dhhc_data *iis3dhhc = dev->data;
	struct sensor_trigger drdy_trigger = {
		.type = SENSOR_TRIG_DATA_READY,
	};
	const struct iis3dhhc_config *cfg = dev->config;

	if (iis3dhhc->handler_drdy != NULL) {
		iis3dhhc->handler_drdy(dev, &drdy_trigger);
	}

	gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
}

static void iis3dhhc_gpio_callback(const struct device *dev,
				    struct gpio_callback *cb, uint32_t pins)
{
	struct iis3dhhc_data *iis3dhhc =
		CONTAINER_OF(cb, struct iis3dhhc_data, gpio_cb);
	const struct iis3dhhc_config *cfg = iis3dhhc->dev->config;

	ARG_UNUSED(pins);

	gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_DISABLE);

#if defined(CONFIG_IIS3DHHC_TRIGGER_OWN_THREAD)
	k_sem_give(&iis3dhhc->gpio_sem);
#elif defined(CONFIG_IIS3DHHC_TRIGGER_GLOBAL_THREAD)
	k_work_submit(&iis3dhhc->work);
#endif /* CONFIG_IIS3DHHC_TRIGGER_OWN_THREAD */
}

#ifdef CONFIG_IIS3DHHC_TRIGGER_OWN_THREAD
static void iis3dhhc_thread(struct iis3dhhc_data *iis3dhhc)
{
	while (1) {
		k_sem_take(&iis3dhhc->gpio_sem, K_FOREVER);
		iis3dhhc_handle_interrupt(iis3dhhc->dev);
	}
}
#endif /* CONFIG_IIS3DHHC_TRIGGER_OWN_THREAD */

#ifdef CONFIG_IIS3DHHC_TRIGGER_GLOBAL_THREAD
static void iis3dhhc_work_cb(struct k_work *work)
{
	struct iis3dhhc_data *iis3dhhc =
		CONTAINER_OF(work, struct iis3dhhc_data, work);

	iis3dhhc_handle_interrupt(iis3dhhc->dev);
}
#endif /* CONFIG_IIS3DHHC_TRIGGER_GLOBAL_THREAD */

int iis3dhhc_init_interrupt(const struct device *dev)
{
	struct iis3dhhc_data *iis3dhhc = dev->data;
	const struct iis3dhhc_config *cfg = dev->config;
	int ret;

	if (!device_is_ready(cfg->int_gpio.port)) {
		LOG_ERR("%s: device %s is not ready", dev->name, cfg->int_gpio.port->name);
		return -ENODEV;
	}

	iis3dhhc->dev = dev;

#if defined(CONFIG_IIS3DHHC_TRIGGER_OWN_THREAD)
	k_sem_init(&iis3dhhc->gpio_sem, 0, K_SEM_MAX_LIMIT);

	k_thread_create(&iis3dhhc->thread, iis3dhhc->thread_stack,
		       CONFIG_IIS3DHHC_THREAD_STACK_SIZE,
		       (k_thread_entry_t)iis3dhhc_thread, iis3dhhc,
		       NULL, NULL, K_PRIO_COOP(CONFIG_IIS3DHHC_THREAD_PRIORITY),
		       0, K_NO_WAIT);
#elif defined(CONFIG_IIS3DHHC_TRIGGER_GLOBAL_THREAD)
	iis3dhhc->work.handler = iis3dhhc_work_cb;
#endif /* CONFIG_IIS3DHHC_TRIGGER_OWN_THREAD */

	ret = gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT);
	if (ret < 0) {
		LOG_DBG("Could not configure gpio");
		return ret;
	}

	gpio_init_callback(&iis3dhhc->gpio_cb, iis3dhhc_gpio_callback, BIT(cfg->int_gpio.pin));

	if (gpio_add_callback(cfg->int_gpio.port, &iis3dhhc->gpio_cb) < 0) {
		LOG_DBG("Could not set gpio callback");
		return -EIO;
	}

	/* enable interrupt on int1/int2 in pulse mode */
	if (iis3dhhc_drdy_notification_mode_set(iis3dhhc->ctx, IIS3DHHC_PULSED)) {
		return -EIO;
	}

	return gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
}


text:
Rickshaw.namespace('Rickshaw.Graph.Axis.X');

Rickshaw.Graph.Axis.X = function(args) {

	var self = this;
	var berthRate = 0.10;

	this.initialize = function(args) {

		this.graph = args.graph;
		this.orientation = args.orientation || 'top';

		this.pixelsPerTick = args.pixelsPerTick || 75;
		if (args.ticks) this.staticTicks = args.ticks;
		if (args.tickValues) this.tickValues = args.tickValues;

		this.tickSize = args.tickSize || 4;
		this.ticksTreatment = args.ticksTreatment || 'plain';

		if (args.element) {

			this.element = args.element;
			this._discoverSize(args.element, args);

			this.vis = d3.select(args.element)
				.append("svg:svg")
				.attr('height', this.height)
				.attr('width', this.width)
				.attr('class', 'rickshaw_graph x_axis_d3');

			this.element = this.vis[0][0];
			this.element.style.position = 'relative';

			this.setSize({ width: args.width, height: args.height });

		} else {
			this.vis = this.graph.vis;
		}

		this.graph.onUpdate( function() { self.render() } );
	};

	this.setSize = function(args) {

		args = args || {};
		if (!this.element) return;

		this._discoverSize(this.element.parentNode, args);

		this.vis
			.attr('height', this.height)
			.attr('width', this.width * (1 + berthRate));

		var berth = Math.floor(this.width * berthRate / 2);
		this.element.style.left = -1 * berth + 'px';
	};

	this.render = function() {

		if (this.graph.width !== this._renderWidth) this.setSize({ auto: true });

		var axis = d3.svg.axis().scale(this.graph.x).orient(this.orientation);
		axis.tickFormat( args.tickFormat || function(x) { return x } );
		if (this.tickValues) axis.tickValues(this.tickValues);

		this.ticks = this.staticTicks || Math.floor(this.graph.width / this.pixelsPerTick);

		var berth = Math.floor(this.width * berthRate / 2) || 0;
		var transform;

		if (this.orientation == 'top') {
			var yOffset = this.height || this.graph.height;
			transform = 'translate(' + berth + ',' + yOffset + ')';
		} else {
			transform = 'translate(' + berth + ', 0)';
		}

		if (this.element) {
			this.vis.selectAll('*').remove();
		}

		this.vis
			.append("svg:g")
			.attr("class", ["x_ticks_d3", this.ticksTreatment].join(" "))
			.attr("transform", transform)
			.call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));

		var gridSize = (this.orientation == 'bottom' ? 1 : -1) * this.graph.height;

		this.graph.vis
			.append("svg:g")
			.attr("class", "x_grid_d3")
			.call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize));

		this._renderHeight = this.graph.height;
	};

	this._discoverSize = function(element, args) {

		if (typeof window !== 'undefined') {

			var style = window.getComputedStyle(element, null);
			var elementHeight = parseInt(style.getPropertyValue('height'), 10);

			if (!args.auto) {
				var elementWidth = parseInt(style.getPropertyValue('width'), 10);
			}
		}

		this.width = (args.width || elementWidth || this.graph.width) * (1 + berthRate);
		this.height = args.height || elementHeight || 40;
	};

	this.initialize(args);
};


text:
import { fromJS } from 'immutable'

import async from 'async'
import Api from 'Api'
import { actions as apiActions } from 'Api/reducer'

// ------------------------------------
// Constants *** WNI
// ------------------------------------
export const WNI_VIEW_INPUT_CHANGE = 'WNI_VIEW_INPUT_CHANGE'
export const WNI_VIEW_LOGOUT_SUCCESS = 'WNI_VIEW_LOGOUT_SUCCESS'
export const WNI_VIEW_LOGOUT_ERROR = 'WNI_VIEW_LOGOUT_ERROR'
export const WNI_VIEW_SUCCESS = 'WNI_VIEW_SUCCESS'
export const WNI_VIEW_ERROR = 'WNI_VIEW_ERROR'
export const WNI_VIEW_FORM_ID = 'WNI_VIEW_FORM_ID'
export const WNI_VIEW_FORM_INPUT_CHANGE = 'WNI_VIEW_FORM_INPUT_CHANGE'
export const WNI_VIEW_FORM_VALUES = 'WNI_VIEW_FORM_VALUES'
export const WNI_VIEW_FORM_TICKETS = 'WNI_VIEW_FORM_TICKETS'
export const WNI_VIEW_FORM_MERGEIN_TICKETS = 'WNI_VIEW_FORM_MERGEIN_TICKETS'

// ------------------------------------
// Actions
// ------------------------------------

export function noop () {
  return {
    type: 'NOOP',
  }
}

export function inputChange (name, val) {
  return {
    type: WNI_VIEW_INPUT_CHANGE,
    name,
    val,
  }
}

export function formInputChange (name, val) {
  return {
    type: WNI_VIEW_FORM_INPUT_CHANGE,
    name,
    val,
  }
}

export function setFormId(formId) {
  return (dispatch, getState) => {
    dispatch({
      type: WNI_VIEW_FORM_ID,
      formId,
    })

    dispatch(apiActions.getWniById(formId))
    .then((formValues) => {
      if (formValues.error || formValues.statusCode)
        return

      console.log('formData', formValues)

      dispatch({
        type: WNI_VIEW_FORM_VALUES,
        formValues: fromJS(formValues),
      })

      async.parallel(getImages(formValues, dispatch), (err, results) => {

        formValues = fromJS(Object.assign(formValues, results))

        dispatch({
          type: WNI_VIEW_FORM_VALUES,
          formValues,
        })
      })

    })
  }
}

// completely the same as the code in the formEdit
const getImages = (formValues, dispatch) => {
  if (!formValues)
    return {}

  var imageObj = Object.keys(formValues).reduce((result, item) => {
    if (item.match(/^file_/)) {
      result[item.replace('file_','')] = (cb) => {
        var fileParam = {
          container: formValues.type,
          filename: formValues[item],
        }
        dispatch(apiActions.getImage(fileParam))
          .then((imgDataURI) => {
            if (imgDataURI.error || imgDataURI.statusCode)
              return cb(imgDataURI)
            cb(null, imgDataURI)
          })
      }
    }
    return result
  }, {})
  return imageObj
}

export const sendMessage = () => {
  return (dispatch, getState) => {
    var message = getState().formView.get('ticketMessage')
    var formId = getState().formView.get('formId')
    var formUserId = getState().formView.getIn(['formValues', 'userId'])
    return dispatch(apiActions.addTicket(formId, formUserId, message))
    .then((ticket)=> {
      if (ticket.error || ticket.statusCode) {
        dispatch(noop)
        // XXX should display an error
      }
      else {
        let tickets = fromJS({[ticket.id]: ticket })
        dispatch({
          type: WNI_VIEW_FORM_MERGEIN_TICKETS,
          tickets,
        })
        dispatch(inputChange('ticketMessage', ''))
      }
    })
  }
}
/*  This is a thunk, meaning it is a function that immediately
    returns a function for lazy evaluation. It is incredibly useful for
    creating async actions, especially when combined with redux-thunk! */

export const updateWni = (status) => {
  return (dispatch, getState) => {
    var currentUser = getState().api.getIn(['token','user','username'])
    var formValues = getState().formView.get('formValues').toJS()
    var origFormValues = getState().formView.get('formValues').toJS()

    var formAttributes = {
      id: formValues.id,
      ticketStatus: status,
      checkedBy: currentUser,
      checkedTime: new Date()
    }

    if (formValues.lat && formValues.lng) {
      Object.assign(formAttributes, {lat: formValues.lat, lng: formValues.lng})
    }

    dispatch(apiActions.patchWni(formAttributes))
    .then((updatedValues) => {
      if (updatedValues.error || updatedValues.statusCode) {
        return dispatch(inputChange('message', updatedValues.message))
      }

      dispatch({
        type: 'WNI_VIEW_SUCCESS',
        message: 'Form telah diperbarui'
      })

    })

  }
}

export const logout = () => {
  return apiActions.logout()
}

export const actions = {
  noop,
  inputChange,
  // getOpenForms: apiActions.getOpenForms,
  // getTickets: apiActions.getTickets,
}

// ------------------------------------
// Action Handlers
// ------------------------------------
const ACTION_HANDLERS = {
  [WNI_VIEW_FORM_ID] : (state, action) => {
    return state.set('formId', action.formId)
  },

  [WNI_VIEW_FORM_VALUES] : (state, action) => {
    return state
      .merge({submitted: false, message: '', ticketMessage: ''})
      .setIn(['formValues'], action.formValues)
      .setIn(['origFormValues'], action.formValues)
  },

  [WNI_VIEW_FORM_INPUT_CHANGE] : (state, action) => {
    return state
      .set('message','')
      .setIn(['formValues', action.name], action.val)
  },

  [WNI_VIEW_FORM_TICKETS] : (state, action) => {
    return state.setIn(['tickets'], action.tickets)
  },

  [WNI_VIEW_FORM_MERGEIN_TICKETS] : (state, action) => {
    return state.mergeIn(['tickets'], action.tickets)
  },

  [WNI_VIEW_INPUT_CHANGE] : (state, action) => {
    // console.log('ST', action, errMsg);
    return state
      .set(action.name, action.val)
  },

  [WNI_VIEW_SUCCESS]  : (state, action) => {
    return state
      .merge({submitted: true, message: action.message})
  },

  [WNI_VIEW_ERROR] : (state, action) => {
    return state
      .merge({submitted: 'error', message: action.message})
  },
}

// ------------------------------------
// Reducer
// ------------------------------------
const initialState = fromJS({
  submitted: false,
  message: '',
  origFormValues: {},
  formValues: {},
  formErrors: {},
  formId: null,
  tickets: {},
  ticketMessage: '',
})

export default function formViewReducer (state = initialState, action) {
  const handler = ACTION_HANDLERS[action.type]

  return handler ? handler(state, action) : state
}


text:
<!DOCTYPE html>

        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title>Seamoth Update - Subnautica</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width initial-scale=1, maximum-scale=1">

        <link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,700,400' rel='stylesheet' type='text/css'>
        <link href='http://fonts.googleapis.com/css?family=Source+Code+Pro' rel='stylesheet' type='text/css'>

        <link rel = "stylesheet" href = "css/bootstrap.min.css">
        <link rel="stylesheet" href="css/swagger.css">
        <link rel="stylesheet" href="css/normalize.css">
        <link rel="stylesheet" href="css/lightbox.css">
        <link rel="stylesheet" href="css/main.css" media="(min-width: 768px)">
        <link rel="stylesheet" href="css/narrow.css" media="(max-width: 767px)">

                        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapsed" aria-expanded="false">
                            Toggle navigation

                        </button>

                            <form action="http://store.steampowered.com/app/264710/" target="_blank">
                                <button class="btn btn-default navbar-btn buy-btn">Buy now on </button>
                            </form>

                            Dev Information

Production Tracker

Bug Tracker

Repository Checkins

Feedback Reports

Feedback Guide

Experimental Updates Guide

Feedback Guide

Technical Support Guide

                                <video autoplay loop muted poster="http://dagpjqx8ho336.cloudfront.net/vid/20150910_SeamothUpdate_BackgroundVid_Still.jpg"
                                id="bgvid"
                                data-anchor-target="#slide-1"
                                data-bottom-top="background-position: 50% 0px"
                                data-top-bottom="background-position: 50% -100px;"
                                data-anchor-target="#slide-1">
                                    <source src="http://dagpjqx8ho336.cloudfront.net/vid/20150910_SeamothUpdate_BackgroundVid_32s.mp4" type = "video/mp4">
                                </video>

Your Survival PDA has been updated with enhanced aquatic mobility solutions, and other essential improvements.

                                    X

CONTROLLER

                                         Here's the situation, people. 37 minutes ago we lost contact with the Aurora. Until every last crewmember is home safe or confirmed dead we are going to do whatever it takes to improve their chances.

ANALYST

                                        We just learned the planet's surface is 97% water. That means we need improved submersibles, diving gear, pressure compensation equipment...

CONTROLLER
And we have a limited window to flash them the data. You all know what to do.

Please familiarize yourself with this short instructional video.

The New Improved Seamoth

The Seamoth is a one-person submersible with independent power systems. Originally designed for industrial mining operations, it has been repurposed for use in survival situations, and product upgrades have expanded its functionality.

Seamoth Upgrade Suite Available

The Seamoth can now be customized with up to 4 different, stackable upgrades, manufactured using the Seamoth Upgrade Console, which has been added to your database.

                                        Upgrade Panel

                                        X

Seamoth Upgrade Access Panel

The most pivotal enhancement is the wing-mounted access point which enables pilots to install upgrade modules to customize their submersible for their particular needs.

                                        Chassis Improvements

                                        X

Seamoth Chassis Improvements

                                        <video autoplay loop muted poster="http://d1xnoqb6cz2ip.cloudfront.net/vid/stills/20150910_SN_SeamothUpdate_GIF_1_SeamothJump_Still.jpg" class="vid vid-responsive">
                                            <source src="http://dagpjqx8ho336.cloudfront.net/vid/20150910_SN_SeamothUpdate_GIF_1_SeamothJump_500.mp4" type = "video/mp4">
                                        </video>

The Seamoth chassis has been made lighter and more aerodynamic, enabling pilots to breach the water and remain airborne for longer.

                                        Crush Depth

                                        X

WARNING: Seamoth Crush Depth

With the enhancements made to the Seamoth, minor structural vulnerabilities were introduced. Without further upgrades the Seamoth is not rated for depths greater than 225 metres.

                                            Storage

                                            X

Seamoth Storage Solution

A 4x4 storage locker fixable to the main hull or to the wings, designed for survivors who must travel great distances to acquire necessary resources.

                                            Power Efficiency Upgrade

                                            X

Power Efficiency Upgrade

This upgrade recycles some of the heat by-product generated by the engine to minimise inefficiencies. Each module reduces power use by 15%.

                                            Pressure Compensator

                                            X

Pressure Compensator

The Seamoth chassis is now built from a smart metal with an adaptable atomic structure which hardens exponentially under programmed conditions. The Pressure Compensator triggers the reaction under extreme atmospheric pressures, and increases safe depth by 200m.

                                            Hull Reinforcement

                                            X

Hull Reinforcement

This upgrade also utilizes the Seamoth's smart-metal hull to reinforce structural integrity, but focuses on collision detection and pre-emptive chassis hardening. Guaranteed to withstand all collisions at normal speeds.

                                            Sonar

                                            X

Sonar

A dedicated system for detecting and displaying topographical data on the HUD. Recommended for scouting difficult terrain and identifying cave entrances.

                                            Perimeter Defense System

                                            X

Perimeter Defense System

A short range, short duration electrical field designed to ward off aggressive fauna.

                                            Torpedo System

                                            X

Torpedo System

A standard underwater payload delivery system adapted to fire non-lethal Vortex Torpedoes.

                                            Solar Charger

                                            X

Solar Charger

Converts UV and visible light into electric charge for the Seamoth's onboard power cell.

                                        X

CONTROLLER

                                         What do we know about the local ecosystem?

ANALYST

                                        Too far for accurate biomass readings, but conditions could support aquatic lifeforms.

CONTROLLER

                                         Ship them the Defense System and the Vortex Torpedoes.

ANALYST

                                        But ma'am, weapon designs violate Directive 7!

CONTROLLER

                                         Directive 7 is there to reduce the risk of survivors turning on one another. If they're going fin-to-fin with alien krakens then I want them prepared, and damn the directives!

Vortex Torpedoes in Detail

                                    <video autoplay loop muted poster="http://d1xnoqb6cz2ip.cloudfront.net/vid/stills/vid5_still_500.jpg" class="vid vid-responsive">
                                        <source src="http://dagpjqx8ho336.cloudfront.net/vid/20150910_SN_SeamothUpdate_GIF_5_Torpedo_500.mp4" type = "video/mp4">
                                    </video>

The payload utilizes gravity distortion technology to generate a vortex which pulls objects towards it before flinging them away. Torpedoes can be constructed at the Seamoth Upgrade Console.

Perimeter Defense System in Detail

When triggered this upgrade draws power from the Seamoth's main battery to generate a powerful electric field in the immediate vicinity. Unlikely to cause serious harm to larger organisms, it is nonetheless an effective emergency deterrent.

Seamoth Upgrade Console Available

This console may now be constructed in the Moonpool, and used to manage the new Seamoth features. It is equipped with a specialised fabricator for building Seamoth Upgrades, in addition to a console for customizing vehicle name and color.

                                        X

ANALYST

                                        Ma'am, the Submersible team is asking whether the color customization options are survival-essential. What should I tell them?

CONTROLLER

Tell them if it takes more time to cut it than leave it they shouldn't be wasting time asking stupid questions!

Terraformer Blueprint Updated

Previous versions of the terraformer were based on the basic flashlight design. This oversight has been corrected.

New Fauna Detected

New Airborne Species: Skyray

The Skyray exhibits some aesthetic and behavioural similarities to the Rabbitray, but all other evidence indicates their genes diverged long ago.

New Aquatic Predator: Biter

Biters are a small, four-eyed aquatic species with two rows of sharp, needle-like teeth. Their size prohibits them from presenting a serious threat to larger creatures on their own, but in a school they will focus their attention on a single individual and feed until there is nothing left.

New Biome Detected: Mountainous Region

Massive lifesigns detected. Elevated land detected. Cave system detected.

PDA Operating System Updated

Creative Mode has been provided for users to safely field test construction features. In this simulation mode you may build any structure at zero cost, and you cannot die.

The tooltip information your PDA provides on items and samples in your possession now contains more actionable detail.

N.B. The PDA is not a replacement for common sense. If you do not look after yourself your performance will suffer. Be vigilant for signs of malnutrition, such as vomiting, dehydration and the slow healing of wounds.

Get development updates

Sign up to the Subnautica development mailing list! Receive a newsletter when Subnautica receives an update like this one.

                                <form action="//subnauti.us6.list-manage.com/subscribe/post?u=bf02bb8619c14d31027c73d97&id=8fa28cd2f4" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>

                                        <input type="email" value="" name="EMAIL" class="form-control" placeholder = "email address" id="mce-EMAIL">

<input type="text" name="b_bf02bb8619c14d31027c73d97_8fa28cd2f4" tabindex="-1" value="">

<input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="btn btn-default">

                                </form>

community |
                                         system status |
                                         copyright |
                                         privacy policy |
                                         youtube & twitch monetisation |
                                         terms of use

© 2015, Unknown Worlds Entertainment. All rights reserved.


text:
package jace.tracker;

import java.util.ArrayList;

/**
 *
 * @author Brendan Robert (BLuRry) brendan.robert@gmail.com
 */
public class Pattern extends ArrayList<Row> {
    String description;     // Not used currently
    int id;
}


text:
python2 "${HYPERDEX_SRCDIR}"/test/runner.py --space="space kv key k attributes map(string, string) v" --daemons=1 -- \
    ruby "${HYPERDEX_SRCDIR}"/test/ruby/DataTypeMapStringString.rb {HOST} {PORT}


text:
<?php

/**
 * tinyDoc class.
 *
 * This class extends TinyButStrong class to work with OpenDocument and Word 2007 documents.
 *
 * This class needs : PHP 5.2
 * This class needs : TinyButStrong class
 * This class needs optionally : ZipArchive from PECL
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @package    tinyDoc
 * @subpackage tinyDoc
 * @author     Olivier Loynet <tinydoc@googlegroups.com>
 * @version    $Id$
 */

class tinyDoc extends clsTinyButStrong
{
  const VERSION     = '1.0.3';

  const PICTURE_DPI = 96;
  const INCH_TO_CM  = 2.54;
  const PIXEL_TO_CM = 0.0264583333; // 2.54 / 96

  private
    $zipMethod         = 'shell',
    $zipBin            = 'zip',
    $unzipBin          = 'unzip',

    $sourcePathname    = '',
    $processDir        = '',
    $processBasename   = '',
    $defaultExtension  = 'odt',
    $xmlFilename       = 'content.xml',

    $defaultCharset    = 'UTF-8',
    $defaultIsEscape   = true,
    $defaultCallback   = '=~encodeData',

    $charset           = 'UTF-8',
    $isEscape          = true,
    $callback          = '=~encodeData',

    $mimetype = array(
      'sxw'  => 'application/vnd.sun.xml.writer',
      'stw'  => 'application/vnd.sun.xml.writer.template',
      'sxg'  => 'application/vnd.sun.xml.writer.global',
      'sxc'  => 'application/vnd.sun.xml.calc',
      'stc'  => 'application/vnd.sun.xml.calc.template',
      'sxi'  => 'application/vnd.sun.xml.impress',
      'sti'  => 'application/vnd.sun.xml.impress.template',
      'sxd'  => 'application/vnd.sun.xml.draw',
      'std'  => 'application/vnd.sun.xml.draw.template',
      'sxm'  => 'application/vnd.sun.xml.math',
      'odt'  => 'application/vnd.oasis.OpenDocument.text',
      'ott'  => 'application/vnd.oasis.OpenDocument.text-template',
      'oth'  => 'application/vnd.oasis.OpenDocument.text-web',
      'odm'  => 'application/vnd.oasis.OpenDocument.text-master',
      'odg'  => 'application/vnd.oasis.OpenDocument.graphics',
      'otg'  => 'application/vnd.oasis.OpenDocument.graphics-template',
      'odp'  => 'application/vnd.oasis.OpenDocument.presentation',
      'otp'  => 'application/vnd.oasis.OpenDocument.presentation-template',
      'ods'  => 'application/vnd.oasis.OpenDocument.spreadsheet',
      'ots'  => 'application/vnd.oasis.OpenDocument.spreadsheet-template',
      'odc'  => 'application/vnd.oasis.OpenDocument.chart',
      'odf'  => 'application/vnd.oasis.OpenDocument.formula',
      'odb'  => 'application/vnd.oasis.OpenDocument.database',
      'odi'  => 'application/vnd.oasis.OpenDocument.image',
      'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
      'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
      'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
      'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
      'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
      'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
      'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
      'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
      'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
      'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
      'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
      'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
      'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
      'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
      'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
      'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
    );

  /**
   * Constructor.
   */
  public function __construct()
  {
  }

  /**
   * Create a new unique file from a source file
   *
   * @param mixed $options  The pathname of source document (empty array by default)
   */
  public function createFrom($options = array())
  {
    $this->setSourcePathname($options);

    // create an unique basename to process the office document
    $this->newUniqueBasename();

    // create an unique directory like basename to zip/unzip files
    if (!mkdir($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename(), 0777, true))
    {
      throw new tinyDocException(sprintf('Can\'t make directory "%s"', $this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename()));
    }
    if (!is_dir($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename()))
    {
      throw new tinyDocException(sprintf('Directory not found "%s"', $this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename()));
    }

    // copy the file source into the process dir with an unique filename
    if (!copy($this->getSourcePathname(), $this->getPathname()))
    {
      if (!file_exists($this->getSourcePathname()))
      {
        throw new tinyDocException(sprintf('Can\'t copy file, source file not found "%s"', $this->getSourcePathname()));
      }
      else
      {
        throw new tinyDocException(sprintf('Can\'t copy file from "%s" to "%s"', $this->getSourcePathname(), $this->getPathname()));
      }
    }

  }

  /**
   * Load the XML file from the current process file as a TBS template
   *
   * @param string $xmlFilename  The XML file (content.xml by default)
   */
  public function loadXml($xmlFilename = 'content.xml')
  {
    $this->setXmlFilename($xmlFilename);

    // unzip the XML file into the current basename process dir
    switch($this->getZipMethod())
    {
      case 'ziparchive':
        $zip = new ZipArchive();
        if ($zip->open($this->getPathname()) === true)
        {
          $zip->extractTo($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename().DIRECTORY_SEPARATOR, array($this->getXmlFilename()));
          $zip->close();
        }
        break;

      case 'shell':
      default:
        $cmd = $this->getUnzipBinary();
        $cmd.= ' '.escapeshellarg($this->getPathname());
        $cmd.= ' -d';
        $cmd.= ' '.escapeshellarg($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename());
        $cmd.= ' '.escapeshellarg($this->getXmlFilename());
        exec($cmd);
        break;
    }

    // test if the XML file exist
    if (!file_exists($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename().DIRECTORY_SEPARATOR.$this->getXmlFilename()))
    {
      throw new tinyDocException(sprintf('Xml file not found "%s"', $this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename().DIRECTORY_SEPARATOR.$this->getXmlFilename()));
    }

    // load the XML file as a TBS template
    $this->ObjectRef = $this;
    $this->LoadTemplate($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename().DIRECTORY_SEPARATOR.$this->getXmlFilename(), $this->getCallback());

    // work around - convert apostrophe in XML file needed for TBS functions
    $this->Source = str_replace(''', '\'', $this->Source);
  }

  /**
   * Merge data with the template file
   *
   * Available options:
   *
   *  - name:       The tag name in the template ('block' by default)
   *  - type:       The tag type in the template ('field' | 'block' - 'block' by default)
   *  - data_type:  The data type ('array' by default)
   *  - charset:    The data charset ('UTF-8' by default)
   *  - is_escape:  If data are escaped (true by default)
   *  - callback:   The callback to encode data ('=~encodeData' by default)
   *
   * @param array  $options    Options
   * @param mixed  $data       Data
   */
  public function mergeXml($options = array(), $data = array())
  {
    $name      = isset($options['name'])      && is_string($options['name'])      ? $options['name']      : 'block';
    $type      = isset($options['type'])      && is_string($options['type'])      ? $options['type']      : 'block';
    $data_type = isset($options['data_type']) && is_string($options['data_type']) ? $options['data_type'] : 'array';

    $this->setCharset (isset($options['charset'])   && is_string($options['charset'])   ? $options['charset']   : $this->getDefaultCharset());
    $this->setIsEscape(isset($options['is_escape']) && is_bool($options['is_escape'])   ? $options['is_escape'] : $this->getDefaultIsEscape());
    $this->setCallback(isset($options['callback'])  && is_string($options['callback'])  ? $options['callback']  : $this->getDefaultCallback());

    switch($type)
    {
      case 'field':
        $this->MergeField($name, $data);
        break;

      case 'block':
      default:
        $this->MergeBlock($name, $data_type, $data);
        break;
    }
  }

  /**
   * Merge data with a TBS field in template
   *
   * @param string $name       TBS field name in template
   * @param mixed  $data       Data to merge
   */
  public function mergeXmlField($name, $data)
  {
    $this->mergeXml(array('name' => $name, 'type' => 'field'), $data);
  }

  /**
   * Merge data with a TBS block in template
   *
   * @param string $name       TBS block name in template
   * @param mixed  $data       Data to merge
   */
  public function mergeXmlBlock($name, $data)
  {
    $this->mergeXml(array('name' => $name, 'type' => 'block'), $data);
  }

  /**
   * Save the result of merged XML file into the current process file
   */
  public function saveXml()
  {
    // get the source result (TBS method)
    $this->Show(TBS_NOTHING);

    // update the result into the current process file
    switch($this->getZipMethod())
    {
      case 'ziparchive':

        $zip = new ZipArchive();
        if ($zip->open($this->getPathname()) === true)
        {
          $zip->addFromString($this->getXmlFilename(), $this->Source);
          $zip->close();
        }
        break;

      case 'shell':
      default:
        // save the merged result
        $fdw = fopen($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename().DIRECTORY_SEPARATOR.$this->getXmlFilename(), "w");
        fwrite($fdw, $this->Source, strlen($this->Source));
        fclose ($fdw);

        // change the current directory to basename in process dir
        $cwd = getcwd();
        chdir($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename().DIRECTORY_SEPARATOR);

        // zip the XML file into the archive
        $cmd = $this->getZipBinary();
        $cmd.= ' -m';
        $cmd.= ' '.escapeshellarg($this->getPathname());
        $cmd.= ' '.escapeshellarg($this->getXmlFilename());
        exec($cmd);

        // get back current directory
        chdir($cwd);
        break;
    }
  }

  /**
   * Encode the data before merge
   *
   * @param  string $encodeData  The data to merge
   *
   * @return string  The encoded data
   */
  public function encodeData($encodeData)
  {
    // XML charset of OpenOffice / OpenDocument / Word 2007 is utf-8
    switch($this->getCharset())
    {
      case 'ISO 8859-1':
      case 'ISO 8859-15':
        $encodeData = utf8_encode($encodeData);
        break;
      case 'UTF-8':
      case 'UTF8':
      default:
        break;
    }

    // convert special XML chars
    $encodeData = str_replace('&' ,'&',  $encodeData); // the '&' has to be the first to convert
    $encodeData = str_replace('\'' ,''', $encodeData);
    $encodeData = str_replace('"' ,'"', $encodeData);

    if ($this->getIsEscape())
    {
      $encodeData = str_replace('<', '<', $encodeData);
      $encodeData = str_replace('>', '>', $encodeData);
    }

    // convert TAB & LF & CR to XML
    switch($this->getExtension())
    {
      case 'docm':
      case 'docx':
      case 'dotm':
      case 'dotx':
        $encodeData = str_replace("\r\n", '</w:t></w:r></w:p><w:p><w:r><w:t>', $encodeData);
        $encodeData = str_replace("\n",   '</w:t></w:r></w:p><w:p><w:r><w:t>', $encodeData);
        $encodeData = str_replace("\r",   '</w:t></w:r></w:p><w:p><w:r><w:t>', $encodeData);
        $encodeData = str_replace("\t",   '</w:t></w:r><w:r><w:tab/><w:t>'   , $encodeData);
        break;

      case 'ods':
      case 'sxc':
        $encodeData = str_replace("\r\n", '</text:p><text:p>' , $encodeData);
        $encodeData = str_replace("\n",   '</text:p><text:p>' , $encodeData);
        $encodeData = str_replace("\r",   '</text:p><text:p>' , $encodeData);
        $encodeData = str_replace("\t",   '<text:tab/>'       , $encodeData);

        // work-around for EURO caracter
        $encodeData = str_replace(chr(0xC2).chr(0x80) , chr(0xE2).chr(0x82).chr(0xAC),  $encodeData);
        break;

      case 'odt':
      case 'sxw':
      default:
        $encodeData = str_replace("\r\n", '<text:line-break/>', $encodeData);
        $encodeData = str_replace("\n",   '<text:line-break/>', $encodeData);
        $encodeData = str_replace("\r",   '<text:line-break/>', $encodeData);
        $encodeData = str_replace("\t",   '<text:tab/>'       , $encodeData);

        // work-around for EURO caracter
        $encodeData = str_replace(chr(0xC2).chr(0x80) , chr(0xE2).chr(0x82).chr(0xAC),  $encodeData);
        break;
    }

    // remove specials chars from 0x00 to 0x1F
    $encodeData = preg_replace('/[\x{00}-\x{1F}]+/u', '', $encodeData);

    return $encodeData;
  }

  /**
   * Create a unique id and set the basename of process file
   */
  public function newUniqueBasename()
  {
    $unique = md5(uniqid(rand(), true));
    $this->setBasename($unique);
  }

  /**
   * Close by remove the current process directory and subdirectory
   */
  public function close()
  {
    // remove the current process directory
    clearstatcache();
    if (is_dir($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename()))
    {
      $this->deltree($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename());
      rmdir($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename());
    }
  }

  /**
   * Remove a directory and his contents recursively
   *
   * @param string $dir  The pathname the directory
   */
  private function deltree($dir)
  {
    if (realpath($dir) == realpath(DIRECTORY_SEPARATOR))
    {
      return false;
    }

    foreach(glob($dir.DIRECTORY_SEPARATOR.'*') as $filename)
    {
      if (is_dir($filename) && !is_link($filename))
      {
        $this->deltree($filename);
        if (is_writable($filename))
        {
          rmdir($filename);
        }
      }
      else
      {
        if (is_writable($filename))
        {
          unlink($filename);
        }
      }
    }
  }

  /**
   * Remove the current process file
   */
  public function remove()
  {
    unlink($this->getPathname());
  }

  /**
   * Add an external file into the current process file
   *
   * GIF images are not supported in WORD 2007
   *
   * @param string $sourcePathname   The pathname of the source file to add
   * @param string $archivePathname  The pathname in the archive
   */
  public function addFile($sourcePathname, $archivePathname)
  {
    if (file_exists($sourcePathname))
    {
      switch($this->getZipMethod())
      {
        case 'ziparchive':
          $zip = new ZipArchive();
          if ($zip->open($this->getPathname()) === true)
          {
            // don't work - archive corrupted
            // $zip->addFile($sourcePathname, $archivePathname);

            $zip->addFromString($archivePathname, file_get_contents($sourcePathname, false));
            $zip->close();
          }

          break;

        case 'shell':
        default:
          $dir = dirname($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename().DIRECTORY_SEPARATOR.$archivePathname);
          if (!file_exists($dir))
          {
            mkdir($dir, 0777, true);
          }

          if (copy($sourcePathname, $this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename().DIRECTORY_SEPARATOR.$archivePathname))
          {
            // change the current directory to basename in process dir
            $cwd = getcwd();
            chdir($this->getProcessDir().DIRECTORY_SEPARATOR.$this->getBasename().DIRECTORY_SEPARATOR);

            // zip the file into the archive
            $cmd = $this->getZipBinary();
            $cmd.= ' -u';
            $cmd.= ' '.escapeshellarg($this->getPathname());
            $cmd.= ' '.escapeshellarg($archivePathname);
            exec($cmd);

            // get back current directory
            chdir($cwd);
          }
          break;
      }
    }
  }

  /**
   * This function is obsolete, use parameter 'image' to merge pictures.
   *
   * Hack to change in the XML source the tags for image. Only tags with [*.src] work.
   * The TBS tag need to set with OpenOffice into the title field of the image property.
   *
   * Experimental : only for OpenDocument/OpenOffice. Image in blocks don't work with spreadsheet.
   */
  public function tagXmlImage()
  {
    $doc = new DOMDocument();
    $doc->loadXML($this->Source);
    $draw_frames = $doc->getElementsByTagName('frame'); // draw:frame

    foreach ($draw_frames as $draw_frame)
    {
      $svg_titles = $draw_frame->getElementsByTagName('title'); //svg:title
      if ($svg_titles->length > 0)
      {
        $tag = $svg_titles->item(0)->nodeValue;
        if (preg_match('/\[.*src\]/', $tag))
        {
          $draw_images = $draw_frame->getElementsByTagName('image'); // draw:image
          if ($draw_images->length > 0)
          {
            $draw_image = $draw_images->item(0);
            $draw_image->removeAttribute('href'); // xlink:href
            $draw_image->setAttribute('xlink:href', $tag);
          }
        }
      }
    }
    $this->Source = $doc->saveXML();
  }

  /**
   * Send the response
   */
  public function sendResponse($options = array())
  {
    header('Content-Type: '.$this->getMimetype());
    header('Content-Disposition: attachment; filename="'.$this->getDownloadFilename().'"');
    header('Content-Length: '.$this->getSize());
    echo $this->getContent();
  }

  /**
   * Get the basename of the current process file
   *
   * @return string The basename
   */
  public function getBasename()
  {
    return $this->processBasename;
  }

  /**
   * Get the callback method to encode data
   *
   * @return string The callback method
   */
  public function getCallback()
  {
    return $this->callback;
  }

  /**
   * Get the charset of data to be merged
   *
   * @return string The charset
   */
  public function getCharset()
  {
    return $this->charset;
  }

  /**
   * Get the binary content of the current process file
   *
   * @return stream The binary content
   */
  public function getContent()
  {
    return file_get_contents($this->getPathname(), false);
  }

  /**
   * Get the default callback method to encode data
   *
   * @return string  The default callback method
   */
  public function getDefaultCallback()
  {
    return $this->defaultCallback;
  }

  /**
   * Get the default charset of data
   *
   * @return string  The default charset
   */
  public function getDefaultCharset()
  {
    return $this->defaultCharset;
  }

  /**
   * Get the default extension of source file
   *
   * @return string The default extension
   */
  public function getDefaultExtension()
  {
    return $this->defaultExtension;
  }

  /**
   * Get the default if data are escaped
   *
   * @return string The default
   */
  public function getDefaultIsEscape()
  {
    return $this->defaultIsEscape;
  }

  /**
   * Get the filename to download as the current template by default
   *
   * @return string The download filename
   */
  public function getDownloadFilename($options = array())
  {
    return basename($this->getSourcePathname());
  }

  /**
   * Get the extension of the current process file
   *
   * @return string The extension
   */
  public function getExtension()
  {
    $info = pathinfo($this->getSourcePathname());

    return $info['extension'];
  }

  /**
   * Get the filename of the current process file
   *
   * @return string The filename
   */
  public function getFilename()
  {
    return $this->getBasename().'.'.$this->getExtension();
  }

  /**
   * Get if data are escaped
   *
   * @return boolean
   */
  public function getIsEscape()
  {
    return $this->isEscape;
  }

  /**
   * Get the mimetype of the current process file
   *
   * @return string The mimetype
   */
  public function getMimetype()
  {
    return isset($this->mimetype[$this->getExtension()]) ? $this->mimetype[$this->getExtension()] : null;
  }

  /**
   * Get the pathname of the current process file
   *
   * @return string The pathname
   */
  public function getPathname()
  {
    return $this->getProcessDir().DIRECTORY_SEPARATOR.$this->getFilename();
  }

  /**
   * Get the process directory
   *
   * @return string The process dir pathname
   */
  public function getProcessDir()
  {
    return $this->processDir;
  }

  /**
   * Get the size of the current process file
   *
   * @return int The size
   */
  public function getSize()
  {
    return filesize($this->getPathname());
  }

  /**
   * Get the source file pathname
   *
   * @return string The source file pathname
   */
  public function getSourcePathname()
  {
    return $this->sourcePathname;
  }

  /**
   * Get the unzip binary pathfile
   *
   * @return string The unzip binary
   */
  public function getUnzipBinary()
  {
    return $this->unzipBin;
  }

  /**
   * Get the current XML filename
   *
   * @return string The XML filename
   */
  public function getXmlFilename()
  {
    return $this->xmlFilename;
  }

  /**
   * Get the zip binary pathfile
   *
   * @return string The zip binary
   */
  public function getZipBinary()
  {
    return $this->zipBin;
  }

  /**
   * Get the method name to zip/unzip
   *
   * @return string The zip method name
   */
  public function getZipMethod()
  {
    return $this->zipMethod;
  }

  /**
   * Set the basename of the current process file
   *
   * @param  string $basename  The basename
   */
  public function setBasename($basename)
  {
    return $this->processBasename = $basename;
  }

  /**
   * Set the callback method to encode merged data
   *
   * @param  string $callback  The callback method (TBS syntax)
   */
  public function setCallback($callback)
  {
    $this->callback = $callback;
  }

  /**
   * Set the charset
   *
   * @param  string $charset  The charset of the data to merge (utf-8 by default)
   */
  public function setCharset($charset = 'UTF-8')
  {
    $this->charset = strtoupper($charset);
  }

  /**
   * Set if '<' & '>' in merged data are escaped by '<' & '>'
   *
   * BE CAREFUL TO SET TO FALSE
   *
   * @param  boolean $isEscape  Escape data (true by default)
   */
  public function setIsEscape($isEscape = true)
  {
    $this->isEscape = $isEscape;
  }

  /**
   * Set the source file pathname
   *
   * @param mixed $options  The sourcePathname
   */
  public function setSourcePathname($options = array())
  {
    $sourcePathname = $options;

    // test if file exist
    if (!file_exists($sourcePathname))
    {
      throw new tinyDocException(sprintf('File not found "%s"', $sourcePathname));
    }

    // test if file readable
    if (!is_readable($sourcePathname))
    {
      throw new tinyDocException(sprintf('File not readable "%s"', $sourcePathname));
    }

    $this->sourcePathname = $sourcePathname;
  }

  /**
   * Set the process directory
   *
   * @param  string $processDir  The pathname of the process dir
   */
  public function setProcessDir($processDir = 'tmp')
  {
    if (realpath($processDir) == realpath(DIRECTORY_SEPARATOR))
    {
      throw new tinyDocException(sprintf('Could not use the root for the process directory "%s"', $processDir));
    }
    if (!is_dir(realpath($processDir)))
    {
      throw new tinyDocException(sprintf('Process directory not found "%s"', $processDir));
    }
    if (!is_writable(realpath($processDir)))
    {
      throw new tinyDocException(sprintf('Process directory not writable "%s"', $processDir));
    }

    $this->processDir = rtrim(realpath($processDir), DIRECTORY_SEPARATOR);
  }

  /**
   * Fix the unzip binary
   *
   * @param  string  $unzipBin  The pathname of the unzip binary (unzip by default)
   */
  public function setUnzipBinary($unzipBinary = 'unzip')
  {
    if ($this->getZipMethod() == 'shell')
    {
      $unzipBinary = self::escapeShellCommand($unzipBinary);

      if (strlen(shell_exec($unzipBinary.' -h')) == 0)
      {
        throw new tinyDocException(sprintf('"%s" not executable', $unzipBinary));
      }

      $this->unzipBin = $unzipBinary;
    }
  }

  /**
   * Set the XML filename of the current template
   *
   * @param string The pathname of XML filename (content.xml by default)
   */
  public function setXmlFilename($xmlFilename = 'content.xml')
  {
    $this->xmlFilename = $xmlFilename;
  }

  /**
   * Fix the zip binary
   *
   * @param  string  $zipBin  The pathname of the zip binary (zip by default)
   */
  public function setZipBinary($zipBinary = 'zip')
  {
    if ($this->getZipMethod() == 'shell')
    {
      $zipBinary = self::escapeShellCommand($zipBinary);

      if (strlen(shell_exec($zipBinary.' -h')) == 0)
      {
        throw new tinyDocException(sprintf('"%s" not executable', $zipBinary));
      }

      $this->zipBin = $zipBinary;
    }
  }

  /**
   * Fix the method to zip/unzip file.
   *
   * @param  string  $zipMethod  The method are 'shell' or 'ziparchive' (shell by default)
   */
  public function setZipMethod($zipMethod = 'shell')
  {
    $method = strtolower($zipMethod);

    if (!in_array($method, array('shell', 'ziparchive')))
    {
      throw new tinyDocException(sprintf('Zip method "%s" need to be \'shell\' or \'ziparchive\'', $method));
    }

    if ($method == 'ziparchive' && !class_exists('ZipArchive'))
    {
      throw new tinyDocException('Zip extension not loaded - check your php settings, PHP 5.2 minimum with zip extension is required');
    }

    $this->zipMethod = $method;
  }

  /**
   * Redefinition of TBS method to make an exception when an alert occured
   *
   * @param  string $Src       TBS subject ???
   * @param  string $Msg       TBS message ???
   * @param  string $NoErrMsg  TBS no error message ???
   * @param  string $SrcType   The TBS source type ???
   */
  public function meth_Misc_Alert($Src, $Msg, $NoErrMsg=false, $SrcType=false)
  {
    throw new tinyDocException(sprintf('%s', $Msg));
  }

  /**
   * Redefinition of TBS method to add parameter 'cell' to set value with native OpenDocument format in spreadsheet
   *
   * refactoring code from egroupware/perp_api/inc/report/ooo.inc.php
   *
   * @param  string $Txt       TBS source
   * @param  string $Loc       TBS locator
   * @param  string $Value     TBS data to merge
   * @param  string $CheckSub  TBS checksub ???
   */
  public function meth_Locator_Replace(&$Txt, &$Loc, &$Value, $CheckSub)
  {

    if (!isset($Loc->PrmLst['type']) && !isset($Loc->PrmLst['image']) && !isset($Loc->PrmLst['link']))
    {
      return parent::meth_Locator_Replace($Txt, $Loc, $Value, $CheckSub);
    }

    // keep 'Loc' position for the end
    $posBeg = $Loc->PosBeg;
    $posEnd = $Loc->PosEnd;

    // get data
    $data = isset($Value) ? $Value : null;
    foreach($Loc->SubLst as $sub)
    {
      $data = isset($Value[$sub]) ? $Value[$sub] : null ;
    }

    // ----- parameter = type
    if (isset($Loc->PrmLst['type']))
    {
      if ($data == '')
      {
        $Txt = substr_replace($Txt, '', $Loc->PosBeg, $Loc->PosEnd - $Loc->PosBeg + 1 );
        $Loc->PosBeg   = $posBeg;
        $Loc->PosEnd   = $posEnd;
        return $Loc->PosBeg;
      }

      // get container enlarged to table:table-cell
      $Loc->Enlarged    = $this->f_Loc_EnlargeToStr($Txt, $Loc, '<table:table-cell' ,'/table:table-cell>');
      $container    = substr($Txt, $Loc->PosBeg, $Loc->PosEnd - $Loc->PosBeg + 1);

      if ($container == '')
      {
        throw new tinyDocException(sprintf('<table:table-cell not found in document "%s"', $this->getXmlFilename()));
      }

      // OpenOffice attributes cell - see : http://books.evc-cit.info/odbook/ch05.html#table-cells-section
      switch($Loc->PrmLst['type'])
      {
        case 'datetime':
        case 'date':
        case 'dt':
        case 'd':
          $attribute = sprintf('office:value-type="date" office:date-value="%s"', str_replace(' ', 'T', $data));
          break;

        case 'time':
        case 't':
          list($h, $m, $s) = split(":", $data);
          $attribute = sprintf('office:value-type="time" office:time-value="PT%sH%sM%sS"', $h, $m, $s);
          break;

        case 'percentage':
        case 'percent':
        case 'p':
          $attribute = sprintf('office:value-type="percentage" office:value="%s"', $data);
          break;

        case 'currency':
        case 'cur':
        case 'c':
          //$attribute = sprintf('office:value-type="currency" office:currency="EUR" office:value="%s"', $data); // still not necessary to fix the currency
          $attribute = sprintf('office:value-type="currency" office:value="%s"', $data);
          break;

        case 'number':
        case 'n':
        case 'float':
        case 'f':
          $attribute = sprintf('office:value-type="float" office:value="%s"', $data);
          break;

        case 'int':
        case 'i':
          $attribute = sprintf('office:value-type="float" office:value="%d"', $data);
          break;

        default:
        case 'string':
        case 's':
          $attribute = sprintf('office:value-type="string"');
          break;
      }

      // new container
      $newContainer = preg_replace('/office:value-type="string"/', $attribute, $container);

      // replace the new cell containter in the main Txt
      $Txt = substr_replace($Txt, $newContainer, $Loc->PosBeg, $Loc->PosEnd - $Loc->PosBeg + 1 );

      // correct 'Loc' to include the change of the new cell container
      $delta = strlen($newContainer) - strlen($container);
      $Loc->PosBeg   = $posBeg + $delta;
      $Loc->PosEnd   = $posEnd + $delta;
      $Loc->Enlarged = null;
    }

    // ----- parameter = image
    if (isset($Loc->PrmLst['image']))
    {
      // get container enlarged to draw:frame
      $Loc->Enlarged = $this->f_Loc_EnlargeToStr($Txt, $Loc, '<draw:frame' ,'/draw:frame>');
      $container = substr($Txt, $Loc->PosBeg, $Loc->PosEnd - $Loc->PosBeg + 1);

      if ($container == '')
      {
        throw new tinyDocException(sprintf('<draw:frame not found in document "%s"', $this->getXmlFilename()));
      }

      // test if data is empty or if file not exists
      if ($data == '' || !file_exists($data))
      {
        $Txt = substr_replace($Txt, '', $Loc->PosBeg, $Loc->PosEnd - $Loc->PosBeg + 1 );
        $Loc->PosBeg   = $posBeg;
        $Loc->PosEnd   = $posEnd;
        $Loc->Enlarged = null;
        return $Loc->PosBeg;
      }

      $picture = 'Pictures/'.basename($data);

      // image size
      $size = @getimagesize($data);
      if ($size === false)
      {
        throw new tinyDocException(sprintf('Invalid image format "%"', $data));
      }
      else
      {
        list ($width, $height) = $size;
      }

      // image ratio
      $ratio = 1;

      switch(strtolower($Loc->PrmLst['image']))
      {
        case 'fit':
          if (preg_match('/svg:width="(.*?)(cm|in|mm|px)" svg:height="(.*?)(cm|in|mm|px)"/', $container, $matches))
          {
            $ratio_w = self::convertToCm($matches[1], $matches[2]) / self::convertToCm($width, 'px');
            $ratio_h = self::convertToCm($matches[3], $matches[4]) / self::convertToCm($height,'px');
            $ratio = min($ratio_w, $ratio_h);
          }
          break;
        case 'max':
          if (preg_match('/svg:width="(.*?)(cm|in|mm|px)" svg:height="(.*?)(cm|in|mm|px)"/', $container, $matches))
          {
            $ratio_w = self::convertToCm($matches[1], $matches[2]) / self::convertToCm($width, 'px');
            $ratio_h = self::convertToCm($matches[3], $matches[4]) / self::convertToCm($height,'px');
            $ratio = min(1, $ratio_w, $ratio_h);
          }
          break;
        default:
          if (preg_match('/([0-9\.]*)%/', $Loc->PrmLst['image'], $matches) > 0)
          {
            $ratio = $matches[1] / 100;
          }
          break;
      }

      // replace values
      $newContainer = $container;
      $newContainer = preg_replace('/svg:width="(.*?)"/' , sprintf('svg:width="%scm"' , self::convertToCm($width, 'px') * $ratio), $newContainer);
      $newContainer = preg_replace('/svg:height="(.*?)"/', sprintf('svg:height="%scm"', self::convertToCm($height,'px') * $ratio), $newContainer);
      $newContainer = preg_replace('/xlink:href="(.*?)"/', sprintf('xlink:href="%s"'  , $picture), $newContainer);

      // add file
      $this->addFile($data, $picture);

      // replace the new cell containter in the main Txt
      $Txt = substr_replace($Txt, $newContainer, $Loc->PosBeg, $Loc->PosEnd - $Loc->PosBeg + 1);

      $Loc->PosBeg   = $posBeg;
      $Loc->PosEnd   = $posEnd;
      $Loc->Enlarged = null;
    }

    // ----- parameter = link
    if (isset($Loc->PrmLst['link']))
    {
      if ($data == '')
      {
        $Txt = substr_replace($Txt, '', $Loc->PosBeg, $Loc->PosEnd - $Loc->PosBeg + 1 );
        $Loc->PosBeg   = $posBeg;
        $Loc->PosEnd   = $posEnd;
        return $Loc->PosBeg;
      }

      $container = substr($Txt, $Loc->PosBeg, $Loc->PosEnd - $Loc->PosBeg + 1);
      $title = ($Loc->PrmLst['link'] != '1' ? $Loc->PrmLst['link'] : $data);
      $newContainer = sprintf('<text:a xlink:type="simple" xlink:href="%s">%s</text:a>', $data, $title);

      $Txt = substr_replace($Txt, $newContainer, $Loc->PosBeg, $Loc->PosEnd - $Loc->PosBeg + 1);

      // before return, restore 'Loc' with beginning values (to work with block)
      $Loc->PosBeg   = $posBeg;
      $Loc->PosEnd   = $posEnd;
      return $Loc->PosEnd;
    }

    // call the parent method to insert the value
    $ret = parent::meth_Locator_Replace($Txt, $Loc, $Value, $CheckSub);

    // before return, restore 'Loc' with beginning values (to work with block)
    $Loc->PosBeg = $posBeg;
    $Loc->PosEnd = $posEnd;

    return $ret;
  }

  public static function convertToCm($value, $unit)
  {
    switch(strtolower($unit))
    {
      case 'px':
        $returnValue = $value * self::INCH_TO_CM / self::PICTURE_DPI;
        break;
      case 'in':
        $returnValue = $value * self::INCH_TO_CM;
        break;
      case 'mm':
        $returnValue = $value / 10;
        break;
      default;
      case 'cm':
        $returnValue = $value;
        break;
    }

    return $returnValue;
  }

  public static function escapeShellCommand($command)
  {
    if (strpos($command, ' ') !== false)
    {
      $command = (strpos($command, '"') === 0 ? '' : '"').$command;
      $command = $command.((strrpos($command, '"') == strlen($command)-1) ? '' : '"');
    }
    return $command;
  }

}

/**
 * tinyDocException exception class
 *
 * @package    tinyDoc
 * @subpackage tinyDocException
 * @author     Olivier Loynet <tinydoc@googlegroups.com>
 * @version    $Id$
 */
class tinyDocException extends Exception
{
}


text:
import logging
from machine import UART
import time

from .baseio import BaseIO
from ..helpers import get_kwargs

log = logging.getLogger("ESP32IO")

class ESP32IO(BaseIO):
    """
    Uses ESP32 ESP32 for  serial connection, sends command (multiple times if needed)
    and returns the byte_response
    """

    def __init__(self, device_path, serial_baud=2400) -> None:
        self._serial_port = device_path
        self._serial_baud = serial_baud

    def send_and_receive(self, *args, **kwargs) -> dict:
        full_command = get_kwargs(kwargs, "full_command")
        log.info(f"ESP32 serial connection: executing {full_command}")

        response_line = None
        uart_no = self._serial_port.lower().split("esp")[1]
        log.debug(f"port {self._serial_port}, baudrate {self._serial_baud}, uart# {uart_no}")
        try:
            with UART(uart_no, self._serial_baud) as s:
                # Execute command multiple times, increase timeouts each time
                s.init(self._baud_rate, timeout=1000)
                s.write(full_command)
                time.sleep(0.5)  # give serial port time to receive the data
                response_line = s.readline()
                log.debug("esp32 serial response was: %s", response_line)
                return response_line
        except Exception as e:
            log.warning("ESP32 Serial read error: {}".format(e))
        log.info("Command execution failed")
        return {"ERROR": ["Serial command execution failed", ""]}


text:
using System;

partial class Tetromino : MovingObject
{
    public TetrominoType Type { get; private set; }

    private Tetromino(char[,] image, Color color, Coordinates position, TetrominoType type)
        : base(image, color, position)
    {
        this.Type = type;
    }

    public override void Rotate()
    {
        if (this.Type == TetrominoType.O)
            throw new OTetrominoRotatedException();

        base.Rotate();
    }
}