text:
function optionsPageLoaded() {
  var hasLoaded = false;
  chrome.extension.getViews().forEach(function(view) {
    if (view.document.location.pathname == '/options.html') {
      chrome.test.assertEq(false, hasLoaded);
      hasLoaded = view.loaded;
    }
  });
  return hasLoaded;
}

chrome.test.runTests([
  // Basic tests that ensure that the <extensionoptions> guest view is created
  // and loaded, and that the load event is accurate.
  // createGuestViewDOM tests that it can be created and manipulated like a DOM
  // element, and createGuestViewProgrammatic tests the same but as a JavaScript
  // object.
  function createGuestViewDOM() {
    var extensionoptions = document.createElement('extensionoptions');
    extensionoptions.addEventListener('load', function() {
      try {
        chrome.test.assertTrue(optionsPageLoaded());
        chrome.test.succeed();
      } finally {
        document.body.removeChild(extensionoptions);
      }
    });
    extensionoptions.setAttribute('extension', chrome.runtime.id);
    document.body.appendChild(extensionoptions);
  },

  function createGuestViewProgrammatic() {
    var extensionoptions = new ExtensionOptions();
    extensionoptions.onload = function() {
      try {
        chrome.test.assertTrue(optionsPageLoaded());
        chrome.test.succeed();
      } finally {
        document.body.removeChild(extensionoptions);
      }
    };
    extensionoptions.extension = chrome.runtime.id;
    document.body.appendChild(extensionoptions);
  },

  // Tests if the <extensionoptions> guest view is successfully created and can
  // communicate with the embedder. This test expects that the guest options
  // page will add a {'pass': true} property to every Window and fire the
  // runtime.onMessage event with a short message.
  function canCommunicateWithGuest() {
    var done = chrome.test.listenForever(chrome.runtime.onMessage,
        function(message, sender, sendResponse) {
      if (message == 'ready') {
        sendResponse('canCommunicateWithGuest');
      } else if (message == 'done') {
        try {
          var views = chrome.extension.getViews();
          chrome.test.assertEq(2, views.length);
          views.forEach(function(view) {
            chrome.test.assertTrue(view.pass);
          });
          chrome.test.assertEq(chrome.runtime.id, sender.id);
          done();
        } finally {
          document.body.removeChild(extensionoptions);
        }
      }
    });

    var extensionoptions = document.createElement('extensionoptions');
    extensionoptions.setAttribute('extension', chrome.runtime.id);
    document.body.appendChild(extensionoptions);
  },

  // Tests if the <extensionoptions> guest view can access the chrome.storage
  // API, a privileged extension API.
  function guestCanAccessStorage() {
    var onStorageChanged = false;
    var onSetAndGet = false;

    chrome.test.listenOnce(chrome.storage.onChanged, function(change) {
      chrome.test.assertEq(42, change.test.newValue);
    });

    // Listens for messages from the options page.
    var done = chrome.test.listenForever(chrome.runtime.onMessage,
        function(message, sender, sendResponse) {
      // Options page is waiting for a command
      if (message == 'ready') {
        sendResponse('guestCanAccessStorage');
      // Messages from the options page containing test data
      } else if (message.description == 'onStorageChanged') {
        chrome.test.assertEq(message.expected, message.actual);
        onStorageChanged = true;
      } else if (message.description == 'onSetAndGet') {
        chrome.test.assertEq(message.expected, message.actual);
        onSetAndGet = true;
      }

      if (onStorageChanged && onSetAndGet) {
        document.body.removeChild(extensionoptions);
        done();
      }
    });

    var extensionoptions = document.createElement('extensionoptions');
    extensionoptions.setAttribute('extension', chrome.runtime.id);
    document.body.appendChild(extensionoptions);
  },

  function autosizedGuestIsWithinSizeConstraints() {
    var done = chrome.test.callbackAdded();

    var extensionoptions = new ExtensionOptions();
    extensionoptions.extension = chrome.runtime.id;
    extensionoptions.autosize = 'on';
    extensionoptions.minheight = 499;
    extensionoptions.minwidth = 499;
    extensionoptions.maxheight = 501;
    extensionoptions.maxwidth = 501;

    extensionoptions.onsizechanged = function(evt) {
      try {
        chrome.test.assertTrue(evt.width >= 499);
        chrome.test.assertTrue(evt.height >= 499);
        chrome.test.assertTrue(evt.width <= 501);
        chrome.test.assertTrue(evt.height <= 501);
        done();
      } finally {
        document.body.removeChild(extensionoptions);
      }
    };

    document.body.appendChild(extensionoptions);
  },

  function externalLinksOpenInNewTab() {
    var done = chrome.test.listenForever(chrome.runtime.onMessage,
        function(message, sender, sendResponse) {
      if (message == 'ready') {
        sendResponse('externalLinksOpenInNewTab');
      } else if (message == 'done') {
        try {
          chrome.tabs.query({url: 'http://www.chromium.org/'}, function(tabs) {
            chrome.test.assertEq(1, tabs.length);
            chrome.test.assertEq('http://www.chromium.org/', tabs[0].url);
            done();
          });
        } finally {
          document.body.removeChild(extensionoptions);
        }
      }
    });

    var extensionoptions = document.createElement('extensionoptions');
    extensionoptions.setAttribute('extension', chrome.runtime.id);
    document.body.appendChild(extensionoptions);
  }
]);

redpajama_set_name: RedPajamaGithub


text:
require 'rails_helper'

RSpec.describe 'Sessions', :type => :request do

  describe 'with correct credentials' do
    before {
      allow(SecureRandom).to receive(:hex).and_return('superRandom')
    }

    let (:password) {'super-secret-123'}
    let (:user) {User.create(email: 'foo@bar.com', password: password, time_zone: 'Berlin')}
    let (:endpoint) {'/sessions'}

    xit 'responds with a newly generated access token' do
      post endpoint, {email: user.email, password: password }.to_json, headers: { 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' }

      expect(response.body).to eq({access_token: 'superRandom'})
    end

    xit 'responds with an existing access token' do
      user.token = 'Foobarrr123'
      user.save!

      post endpoint, {email: user.email, password: password }.to_json, headers: { 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' }
      expect(response.body).to eq({access_token: 'Foobarrr123'})
    end
  end
end


text:
package org.webrtc;

/**
 * Factory for creating webrtc::FecControllerFactory instances.
 */
public interface FecControllerFactoryFactoryInterface {
  /**
   * Dynamically allocates a webrtc::FecControllerFactory instance and returns a pointer to it.
   * The caller takes ownership of the object.
   */
  public long createNative();
}


text:
@implementation PhotosCollection

- (NSString *)titleName {
    return nil;
}

@end


text:
layout: post
title: Final Exam Review Notes
categories: doc
---

## Format

Your final exam will take place during the scheduled final exam period
(Monday, 23 May 2016, 5:30--7:30 pm) in our normal classroom location (S 362).
You will have the full 2 hours to complete the exam.
The final exam consists of two parts, each described separately below.

### Part I
This portion of the exam is closed-book, closed-notes, and no computer use is allowed or required.
It will consist of multiple choice, true-false, and short answer questions.
You should plan to spend about 30 minutes on this portion.

-----

*AFTER* turning in Part I, you will receive Part II of the exam.

-----

### Part II
This portion of the exam is open-book, open-notes, and you may use your computer.
Please come prepared with a power source and functioning MATLAB and Excel installations.

You will have the remaining time to work on this portion of the exam.
It will consist of problems/exercises testing your knowledge of MATLAB and Excel.

*Do not* plan to rely on books/notes---you may run out of time if you are looking everything up.

## Content
The exam will cover the full course outline, but will primarily focus on the second half of the course (after the midterm exam).

A high-level list of topics:

- Analytic vs. Algorithmic Solutions
- Variables and Functions
- Scalars vs. Arrays
- Matrices and Vectors
- Accuracy vs. Precision
- Excel
  - Formatting
  - Formulas
  - Conditional Formatting
  - Plotting
  - Matrix Mathematics (Array Formulas)
- MATLAB
  - Scripts
  - Functions
  - Flowcharting
  - Plotting
  - Writing Data to a File
  - Working with Arrays
- Applications
  - Root Finding
  - Matrix Mathematics
  - Solving Simultaneous Equations
  - Numerical Integration

## Review Problems
These problems are completely optional; they will not be collected or graded.
You may find them useful in studying/practicing for the final exam.

Musto 2009, Problems 1.2, 2.14, 3.20, 4.2, 5.13, 6.15, 9.13, 7.15, 8.15


text:
package com.soulwarelabs.ecmabox.core.htmlunit;

import com.soulwarelabs.ecmabox.api.Sandbox;
import com.soulwarelabs.ecmabox.api.SandboxFactory;
import com.soulwarelabs.ecmabox.api.layout.Layout;
import com.soulwarelabs.ecmabox.convention.Factory;
import com.soulwarelabs.ecmabox.convention.Immutable;
import com.soulwarelabs.ecmabox.convention.Private;

/**
 * Factory for HtmlUnit-specific sandboxes.
 *
 * @see HtmlUnitSandbox
 * @see SandboxFactory
 *
 * @author Ilia Gubarev
 */
@Private
@Immutable
@Factory(HtmlUnitSandbox.class)
public final class HtmlUnitSandboxFactory implements SandboxFactory {

    @Override
    public Sandbox create(final Layout layout) {
        // TODO: implement sandbox creation
        throw new UnsupportedOperationException();
    }
}


text:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml;

namespace WG_ConfigDifficulty
{
    abstract class WGCD_Math
    {
        public abstract void setDefaults();

        public abstract void readXML(XmlNode node);

        public abstract XmlNode generateXML(XmlDocument xmlDoc, string elementName);

        public abstract int calculateReturnValue(int input);
    }
}


text:
'use strict';
/** Requires */
import _              from 'lodash';
import validator      from 'validator';

import mongoose       from 'mongoose';
import MongooseError  from 'mongoose/lib/error';

import bcrypt         from '../libs/bcrypt';

/** Constant */
export const SCHEMA_NAME = 'User';

export const PASSWORD_MIN_LENGTH = 6;
export const PASSWORD_MAX_LENGTH = 64;

export const BCRYPT_ROUNDS = 10;

export const PASSWORD_HASH_TYPES = {
  'BCRYPT': {
    genSalt() {
      return new Promise((resolve, reject) => {
        bcrypt.genSalt(BCRYPT_ROUNDS, (err, salt) => {
          return err ? reject(err) : resolve(salt);
        });
      });
    },
    genSaltSync() {
      return bcrypt.genSaltSync(BCRYPT_ROUNDS);
    },

    passwordHash(password, salt) {
      return new Promise((resolve, reject) => {
        bcrypt.hash(password, salt, (err, encrypted) => {
          return err ? reject(err) : resolve(encrypted);
        });
      });
    },
    passwordHashSync(password, salt) {
      return bcrypt.hashSync(password, salt);
    }
  }
};

export const DEFAULT_PASSWOD_HASH_TYPE_NAME = 'BCRYPT';

export const ERROR_PATH_IS_REQUIRED     = '`{PATH}` is required';
export const ERROR_PATH_ALREADY_USED    = '`{PATH}` already used';
export const ERROR_PATH_MIN_LENGTH      = '`{PATH}` must be less than {MINLENGTH}';
export const ERROR_PATH_MAX_LENGTH      = '`{PATH}` must be greater than {MAXLENGTH}';
export const ERROR_PASSWORD_MIN_LENGTH  = `\`{PATH}\` must be less than ${PASSWORD_MIN_LENGTH}`;
export const ERROR_PASSWORD_MAX_LENGTH  = `\`{PATH}\` must be greater than ${PASSWORD_MAX_LENGTH}`;

const { Schema } = mongoose;

/** Init */
let UserModel;
const UserSchema = new Schema({
  /** Email */
  email: {
    type:       String,
    required:   ERROR_PATH_IS_REQUIRED,
    unique:     ERROR_PATH_ALREADY_USED,
    index:      true,
    validate: [{
      validator: (s) => validator.isEmail(s),
      msg: 'Invalid email'
    }],
    select:     true
  },
  _email: {
    type:       String,
    lowercase:  true,
    unique:     ERROR_PATH_ALREADY_USED,
    index:      true,
    select:     false
  },

  /** Password */
  _hashedPassword: {
    type:       String,
    required:   ERROR_PATH_IS_REQUIRED,
    select:     true
  },
  _salt: {
    type:       String,
    required:   ERROR_PATH_IS_REQUIRED,
    select:     true
  },
  _hashType: {
    type:       String,
    required:   ERROR_PATH_IS_REQUIRED,
    enum:       _.keys(PASSWORD_HASH_TYPES),
    default:    DEFAULT_PASSWOD_HASH_TYPE_NAME,
    select:     true
  },

  isActive: {
    type:       Boolean,
    required:   ERROR_PATH_IS_REQUIRED,
    default:    false,
    select:     true
  },

  /** Roles */
  role: {
    type:       String,
    required:   ERROR_PATH_IS_REQUIRED,
    lowercase:  true,
    enum: [
      'admin',
      'user'
    ],
    default:    'user',
    select:     true
  },

  /** Meta */
  registrationIP: {
    type:       String,
    required:   ERROR_PATH_IS_REQUIRED,
    index:      true,
    validate: [{
      validator: (s) => validator.isIP(s),
      msg: 'Invalid registration IP'
    }],
    default:    '::ffff:127.0.0.1',
    select:     false
  }
}, {
  createdAndUpdated: true
});

/** Virtal */
UserSchema.virtual('password')
  .get(function () {
    return this._password;
  })
  .set(function (password) {
    this._password = password;
  });

/** Pre validate */
// Password
UserSchema.pre('validate', function (next) {
  // Required
  if (!this.password && !this._hashedPassword) {
    this.invalidate('password', ERROR_PATH_IS_REQUIRED, this.password);
  }

  if (this.password && !_.isString(this.password)) {
    this.invalidate('password', new MongooseError.CastError('string', this.password, 'password'));
  }

  // Skip next checks
  if (!this.password) {
    return next();
  }

  // Length
  /**
   * @todo try replace `ERROR_PASSWORD_MIN_LENGTH` and
   *       `ERROR_PASSWORD_MAX_LENGTH` with `ERROR_PATH_MIN_LENGTH` and
   *       `ERROR_PATH_MAX_LENGTH` constants, respectively.
   *       Now `{MINLENGTH}` and `{MAXLENGTH} template values not replaced.
   */
  const passLen = this.password.length;
  if (passLen < PASSWORD_MIN_LENGTH) {
    this.invalidate('password', ERROR_PASSWORD_MIN_LENGTH, this.password, 'minlength');
  } else if (passLen > PASSWORD_MAX_LENGTH) {
    this.invalidate('password', ERROR_PASSWORD_MAX_LENGTH, this.password, 'maxlength');
  }

  next();
});

// Email in lower case
UserSchema.pre('validate', function (next) {
  if (!this.isNew && !this.isModified('email')) {
    return next();
  }

  if (!this.email || !_.isString(this.email)) {
    return next();
  }

  this._email = this.email.toLowerCase();

  next();
});

// Email
UserSchema.pre('validate', function (next) {
  if (!this.isNew && !this.isModified('email')) {
    return next();
  }

  if (!this.email || !_.isString(this.email)) {
    return next();
  }

  UserModel
    .where({
      _email: this.email.toLowerCase()
    })
    .count()
    .then((count) => {
      if (count !== 0) {
        this.invalidate('email', ERROR_PATH_ALREADY_USED, this.email);
      }

      return next();
    })
    .catch((err) => next(err));
});

// Password Hash
UserSchema.pre('validate', function (next) {
  const self = this;

  if (!this.isNew && !this.password) {
    return next();
  }

  if (!this.password || !_.isString(this.password)) {
    return next();
  }

  return (async function () {
    // Set
    self._hashType = DEFAULT_PASSWOD_HASH_TYPE_NAME;

    const salt = await self._genSalt();
    self._salt = salt;

    const encrypted = await self._passwordHash(self.password);
    self._hashedPassword = encrypted;

    next();
  })()
    .catch((err) => next(err));
});

/** Pre find and findOne */
// Find email in lower case
['find', 'findOne'].forEach((method) => {
  UserSchema.pre(method, function (next) {
    if (!this._conditions.email || !_.isString(this._conditions.email)) {
      return next();
    }

    this._conditions._email = this._conditions.email.toLowerCase();
    delete this._conditions.email;

    next();
  });
});

/** Methods */
// Gen salt
UserSchema.methods._genSalt = function () {
  const hash = PASSWORD_HASH_TYPES[this._hashType];

  if (!hash) {
    return Promise.reject(new TypeError(`Unsupported hash type: "${this._hashType}"`));
  }

  return hash.genSalt();
};
UserSchema.methods._genSaltSync = function () {
  const hash = PASSWORD_HASH_TYPES[this._hashType];

  if (!hash) {
    throw new TypeError(`Unsupported hash type: "${this._hashType}"`);
  }

  return hash.genSaltSync();
};

// Password hashing
UserSchema.methods._passwordHash = function (password) {
  const hashType = PASSWORD_HASH_TYPES[this._hashType];

  if (!hashType) {
    return Promise.reject(new TypeError(`Unsupported hash type: "${this._hashType}"`));
  }

  return hashType.passwordHash(password, this._salt);
};
UserSchema.methods._passwordHashSync = function (password) {
  const hashType = PASSWORD_HASH_TYPES[this._hashType];

  if (!hashType) {
    throw new TypeError(`Unsupported hash type: "${this._hashType}"`);
  }

  return hashType.passwordHashSync(password, this._salt);
};

// Validate password
UserSchema.methods.isValidPassword = function (password) {
  return Promise.resolve()
    .then(() => this._passwordHash(password))
    .then((hashedPassword) => hashedPassword === this._hashedPassword);
};
UserSchema.methods.isValidPasswordSync = function (password) {
  return this._passwordHashSync(password) === this._hashedPassword;
};

UserModel = mongoose.model(SCHEMA_NAME, UserSchema);

export default UserModel;


text:
<?php

namespace CatequizandoEtapaCursou\Table;

use Estrutura\Table\AbstractEstruturaTable;

class CatequizandoEtapaCursouTable extends AbstractEstruturaTable{

    public $table = 'catequizando_etapa_cursou';
    public $campos = [
        'id_catequizando_etapa_cursou'=>'id',
        'id_etapa'=>'id_etapa',
        'id_catequizando'=>'id_catequizando',
        'dt_cadastro'=>'dt_cadastro',
    ];

}


text:
<?php
if (isset($this->session->userdata['user'])) {
    ?>

            Comment as

                <input type="text" class="form-control" name='txtguest' value="<?= $this->session->userdata['user'] ?>"
                       disabled>

    <?php
} else {
    ?>

            Name

                <input type="text" class="form-control" name='txtguest' value="<?php echo set_value('txtguest'); ?>">
                <?= form_error("txtguest"); ?>

<?php } ?>

        Comment content

            <?= form_error("txtcontent"); ?>
            <textarea id="txtcontent" name="txtcontent" class="form-control" cols="20"
                      rows="3"><?php echo set_value('txtcontent'); ?></textarea>

            <button id="btn_comment" class="btn btn-default">Create</button>

    <?php foreach ($comments as $comment): ?>

                            <?php
                            if ($comment['user_level'] == 1) {
                                $label = 'guest';
                            } elseif ($comment['user_level'] == 0) {
                                $label = 'guest';
                            } else {
                                $label = 'admin';
                            }
                            if ($comment['comment_guest']) {
                                echo $comment['comment_guest'] . $label;
                            } else {
                                echo $comment['user_name'] . $label;
                            }
                            ?>

                            <?=\Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $comment['comment_time'])->diffForHumans();?>

                        <?= $comment['comment_content'] ?>

        <? //=$comment['user_name'].': '.$comment['comment_guest']?>

        <? //=$comment['comment_content']?>

    <?php endforeach ?>


text:
package org.apache.airavata.registry.core.workflow.catalog.utils;

import java.util.UUID;

public class WorkflowCatalogUtils {
    public static String getID (String name){
        String pro = name.replaceAll("\\s", "");
        return pro + "_" + UUID.randomUUID();
    }
}


text:
pub use self::client::Client;
#[cfg(feature = "dist-server")]
pub use self::server::Server;
#[cfg(feature = "dist-server")]
pub use self::server::{
    ClientAuthCheck, ClientVisibleMsg, Scheduler, ServerAuthCheck, HEARTBEAT_TIMEOUT,
};

mod common {
    #[cfg(any(feature = "dist-client", feature = "dist-server"))]
    use hyperx::header;
    #[cfg(feature = "dist-server")]
    use std::collections::HashMap;
    use std::fmt;

    use crate::dist;

    use crate::errors::*;
    use crate::util::RequestExt;

    // Note that content-length is necessary due to https://github.com/tiny-http/tiny-http/issues/147
    pub trait ReqwestRequestBuilderExt: Sized {
        fn bincode<T: serde::Serialize + ?Sized>(self, bincode: &T) -> Result<Self>;
        fn bytes(self, bytes: Vec<u8>) -> Self;
        fn bearer_auth(self, token: String) -> Self;
    }
    impl ReqwestRequestBuilderExt for reqwest::blocking::RequestBuilder {
        fn bincode<T: serde::Serialize + ?Sized>(self, bincode: &T) -> Result<Self> {
            let bytes =
                bincode::serialize(bincode).context("Failed to serialize body to bincode")?;
            Ok(self.bytes(bytes))
        }
        fn bytes(self, bytes: Vec<u8>) -> Self {
            self.set_header(header::ContentType::octet_stream())
                .set_header(header::ContentLength(bytes.len() as u64))
                .body(bytes)
        }
        fn bearer_auth(self, token: String) -> Self {
            self.set_header(header::Authorization(header::Bearer { token }))
        }
    }
    impl ReqwestRequestBuilderExt for reqwest::RequestBuilder {
        fn bincode<T: serde::Serialize + ?Sized>(self, bincode: &T) -> Result<Self> {
            let bytes =
                bincode::serialize(bincode).context("Failed to serialize body to bincode")?;
            Ok(self.bytes(bytes))
        }
        fn bytes(self, bytes: Vec<u8>) -> Self {
            self.set_header(header::ContentType::octet_stream())
                .set_header(header::ContentLength(bytes.len() as u64))
                .body(bytes)
        }
        fn bearer_auth(self, token: String) -> Self {
            self.set_header(header::Authorization(header::Bearer { token }))
        }
    }

    pub fn bincode_req<T: serde::de::DeserializeOwned + 'static>(
        req: reqwest::blocking::RequestBuilder,
    ) -> Result<T> {
        // Work around tiny_http issue #151 by disabling HTTP pipeline with
        // `Connection: close`.
        let mut res = req.set_header(header::Connection::close()).send()?;
        let status = res.status();
        let mut body = vec![];
        res.copy_to(&mut body)
            .context("error reading response body")?;
        if !status.is_success() {
            Err(anyhow!(
                "Error {} (Headers={:?}): {}",
                status.as_u16(),
                res.headers(),
                String::from_utf8_lossy(&body)
            ))
        } else {
            bincode::deserialize(&body).map_err(Into::into)
        }
    }
    #[cfg(feature = "dist-client")]
    pub async fn bincode_req_fut<T: serde::de::DeserializeOwned + 'static>(
        req: reqwest::RequestBuilder,
    ) -> Result<T> {
        // Work around tiny_http issue #151 by disabling HTTP pipeline with
        // `Connection: close`.
        let res = req.set_header(header::Connection::close()).send().await?;

        let status = res.status();
        let bytes = res.bytes().await?;
        if !status.is_success() {
            let errmsg = format!(
                "Error {}: {}",
                status.as_u16(),
                String::from_utf8_lossy(&bytes)
            );
            if status.is_client_error() {
                anyhow::bail!(HttpClientError(errmsg));
            } else {
                anyhow::bail!(errmsg);
            }
        } else {
            Ok(bincode::deserialize(&*bytes)?)
        }
    }

    #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
    #[serde(deny_unknown_fields)]
    pub struct JobJwt {
        pub job_id: dist::JobId,
    }

    #[derive(Clone, Debug, Serialize, Deserialize)]
    #[serde(deny_unknown_fields)]
    pub enum AllocJobHttpResponse {
        Success {
            job_alloc: dist::JobAlloc,
            need_toolchain: bool,
            cert_digest: Vec<u8>,
        },
        Fail {
            msg: String,
        },
    }
    impl AllocJobHttpResponse {
        #[cfg(feature = "dist-server")]
        pub fn from_alloc_job_result(
            res: dist::AllocJobResult,
            certs: &HashMap<dist::ServerId, (Vec<u8>, Vec<u8>)>,
        ) -> Self {
            match res {
                dist::AllocJobResult::Success {
                    job_alloc,
                    need_toolchain,
                } => {
                    if let Some((digest, _)) = certs.get(&job_alloc.server_id) {
                        AllocJobHttpResponse::Success {
                            job_alloc,
                            need_toolchain,
                            cert_digest: digest.to_owned(),
                        }
                    } else {
                        AllocJobHttpResponse::Fail {
                            msg: format!(
                                "missing certificates for server {}",
                                job_alloc.server_id.addr()
                            ),
                        }
                    }
                }
                dist::AllocJobResult::Fail { msg } => AllocJobHttpResponse::Fail { msg },
            }
        }
    }

    #[derive(Clone, Debug, Serialize, Deserialize)]
    #[serde(deny_unknown_fields)]
    pub struct ServerCertificateHttpResponse {
        pub cert_digest: Vec<u8>,
        pub cert_pem: Vec<u8>,
    }

    #[derive(Clone, Serialize, Deserialize)]
    #[serde(deny_unknown_fields)]
    pub struct HeartbeatServerHttpRequest {
        pub jwt_key: Vec<u8>,
        pub num_cpus: usize,
        pub server_nonce: dist::ServerNonce,
        pub cert_digest: Vec<u8>,
        pub cert_pem: Vec<u8>,
    }
    // cert_pem is quite long so elide it (you can retrieve it by hitting the server url anyway)
    impl fmt::Debug for HeartbeatServerHttpRequest {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            let HeartbeatServerHttpRequest {
                jwt_key,
                num_cpus,
                server_nonce,
                cert_digest,
                cert_pem,
            } = self;
            write!(f, "HeartbeatServerHttpRequest {{ jwt_key: {:?}, num_cpus: {:?}, server_nonce: {:?}, cert_digest: {:?}, cert_pem: [...{} bytes...] }}", jwt_key, num_cpus, server_nonce, cert_digest, cert_pem.len())
        }
    }
    #[derive(Clone, Debug, Serialize, Deserialize)]
    #[serde(deny_unknown_fields)]
    pub struct RunJobHttpRequest {
        pub command: dist::CompileCommand,
        pub outputs: Vec<String>,
    }
}

pub mod urls {
    use crate::dist::{JobId, ServerId};

    pub fn scheduler_alloc_job(scheduler_url: &reqwest::Url) -> reqwest::Url {
        scheduler_url
            .join("/api/v1/scheduler/alloc_job")
            .expect("failed to create alloc job url")
    }
    pub fn scheduler_server_certificate(
        scheduler_url: &reqwest::Url,
        server_id: ServerId,
    ) -> reqwest::Url {
        scheduler_url
            .join(&format!(
                "/api/v1/scheduler/server_certificate/{}",
                server_id.addr()
            ))
            .expect("failed to create server certificate url")
    }
    pub fn scheduler_heartbeat_server(scheduler_url: &reqwest::Url) -> reqwest::Url {
        scheduler_url
            .join("/api/v1/scheduler/heartbeat_server")
            .expect("failed to create heartbeat url")
    }
    pub fn scheduler_job_state(scheduler_url: &reqwest::Url, job_id: JobId) -> reqwest::Url {
        scheduler_url
            .join(&format!("/api/v1/scheduler/job_state/{}", job_id))
            .expect("failed to create job state url")
    }
    pub fn scheduler_status(scheduler_url: &reqwest::Url) -> reqwest::Url {
        scheduler_url
            .join("/api/v1/scheduler/status")
            .expect("failed to create alloc job url")
    }

    pub fn server_assign_job(server_id: ServerId, job_id: JobId) -> reqwest::Url {
        let url = format!(
            "https://{}/api/v1/distserver/assign_job/{}",
            server_id.addr(),
            job_id
        );
        reqwest::Url::parse(&url).expect("failed to create assign job url")
    }
    pub fn server_submit_toolchain(server_id: ServerId, job_id: JobId) -> reqwest::Url {
        let url = format!(
            "https://{}/api/v1/distserver/submit_toolchain/{}",
            server_id.addr(),
            job_id
        );
        reqwest::Url::parse(&url).expect("failed to create submit toolchain url")
    }
    pub fn server_run_job(server_id: ServerId, job_id: JobId) -> reqwest::Url {
        let url = format!(
            "https://{}/api/v1/distserver/run_job/{}",
            server_id.addr(),
            job_id
        );
        reqwest::Url::parse(&url).expect("failed to create run job url")
    }
}

#[cfg(feature = "dist-server")]
mod server {
    use crate::jwt;
    use byteorder::{BigEndian, ReadBytesExt};
    use flate2::read::ZlibDecoder as ZlibReadDecoder;
    use rand::{rngs::OsRng, RngCore};
    use rouille::accept;
    use std::collections::HashMap;
    use std::io::Read;
    use std::net::SocketAddr;
    use std::result::Result as StdResult;
    use std::sync::atomic;
    use std::sync::Mutex;
    use std::thread;
    use std::time::Duration;
    use void::Void;

    use super::common::{
        bincode_req, AllocJobHttpResponse, HeartbeatServerHttpRequest, JobJwt,
        ReqwestRequestBuilderExt, RunJobHttpRequest, ServerCertificateHttpResponse,
    };
    use super::urls;
    use crate::dist::{
        self, AllocJobResult, AssignJobResult, HeartbeatServerResult, InputsReader, JobAuthorizer,
        JobId, JobState, RunJobResult, SchedulerStatusResult, ServerId, ServerNonce,
        SubmitToolchainResult, Toolchain, ToolchainReader, UpdateJobStateResult,
    };
    use crate::errors::*;

    const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(30);
    const HEARTBEAT_ERROR_INTERVAL: Duration = Duration::from_secs(10);
    pub const HEARTBEAT_TIMEOUT: Duration = Duration::from_secs(90);

    fn create_https_cert_and_privkey(addr: SocketAddr) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)> {
        let rsa_key = openssl::rsa::Rsa::<openssl::pkey::Private>::generate(2048)
            .context("failed to generate rsa privkey")?;
        let privkey_pem = rsa_key
            .private_key_to_pem()
            .context("failed to create pem from rsa privkey")?;
        let privkey: openssl::pkey::PKey<openssl::pkey::Private> =
            openssl::pkey::PKey::from_rsa(rsa_key)
                .context("failed to create openssl pkey from rsa privkey")?;
        let mut builder =
            openssl::x509::X509::builder().context("failed to create x509 builder")?;

        // Populate the certificate with the necessary parts, mostly from mkcert in openssl
        builder
            .set_version(2)
            .context("failed to set x509 version")?;
        let serial_number = openssl::bn::BigNum::from_u32(0)
            .and_then(|bn| bn.to_asn1_integer())
            .context("failed to create openssl asn1 0")?;
        builder
            .set_serial_number(serial_number.as_ref())
            .context("failed to set x509 serial number")?;
        let not_before = openssl::asn1::Asn1Time::days_from_now(0)
            .context("failed to create openssl not before asn1")?;
        builder
            .set_not_before(not_before.as_ref())
            .context("failed to set not before on x509")?;
        let not_after = openssl::asn1::Asn1Time::days_from_now(365)
            .context("failed to create openssl not after asn1")?;
        builder
            .set_not_after(not_after.as_ref())
            .context("failed to set not after on x509")?;
        builder
            .set_pubkey(privkey.as_ref())
            .context("failed to set pubkey for x509")?;

        let mut name = openssl::x509::X509Name::builder()?;
        name.append_entry_by_nid(openssl::nid::Nid::COMMONNAME, &addr.to_string())?;
        let name = name.build();

        builder
            .set_subject_name(&name)
            .context("failed to set subject name")?;
        builder
            .set_issuer_name(&name)
            .context("failed to set issuer name")?;

        // Add the SubjectAlternativeName
        let extension = openssl::x509::extension::SubjectAlternativeName::new()
            .ip(&addr.ip().to_string())
            .build(&builder.x509v3_context(None, None))
            .context("failed to build SAN extension for x509")?;
        builder
            .append_extension(extension)
            .context("failed to append SAN extension for x509")?;

        // Add ExtendedKeyUsage
        let ext_key_usage = openssl::x509::extension::ExtendedKeyUsage::new()
            .server_auth()
            .build()
            .context("failed to build EKU extension for x509")?;
        builder
            .append_extension(ext_key_usage)
            .context("failes to append EKU extension for x509")?;

        // Finish the certificate
        builder
            .sign(&privkey, openssl::hash::MessageDigest::sha1())
            .context("failed to sign x509 with sha1")?;
        let cert: openssl::x509::X509 = builder.build();
        let cert_pem = cert.to_pem().context("failed to create pem from x509")?;
        let cert_digest = cert
            .digest(openssl::hash::MessageDigest::sha256())
            .context("failed to create digest of x509 certificate")?
            .as_ref()
            .to_owned();

        Ok((cert_digest, cert_pem, privkey_pem))
    }

    // Messages that are non-sensitive and can be sent to the client
    #[derive(Debug)]
    pub struct ClientVisibleMsg(String);
    impl ClientVisibleMsg {
        pub fn from_nonsensitive(s: String) -> Self {
            ClientVisibleMsg(s)
        }
    }

    pub trait ClientAuthCheck: Send + Sync {
        fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg>;
    }
    pub type ServerAuthCheck = Box<dyn Fn(&str) -> Option<ServerId> + Send + Sync>;

    const JWT_KEY_LENGTH: usize = 256 / 8;
    lazy_static! {
        static ref JWT_HEADER: jwt::Header = jwt::Header::new(jwt::Algorithm::HS256);
        static ref JWT_VALIDATION: jwt::Validation = jwt::Validation {
            leeway: 0,
            validate_exp: false,
            validate_nbf: false,
            aud: None,
            iss: None,
            sub: None,
            algorithms: vec![jwt::Algorithm::HS256],
        };
    }

    // Based on rouille::input::json::json_input
    #[derive(Debug)]
    pub enum RouilleBincodeError {
        BodyAlreadyExtracted,
        WrongContentType,
        ParseError(bincode::Error),
    }
    impl From<bincode::Error> for RouilleBincodeError {
        fn from(err: bincode::Error) -> RouilleBincodeError {
            RouilleBincodeError::ParseError(err)
        }
    }
    impl std::error::Error for RouilleBincodeError {
        fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
            match *self {
                RouilleBincodeError::ParseError(ref e) => Some(e),
                _ => None,
            }
        }
    }
    impl std::fmt::Display for RouilleBincodeError {
        fn fmt(
            &self,
            fmt: &mut std::fmt::Formatter<'_>,
        ) -> std::result::Result<(), std::fmt::Error> {
            write!(
                fmt,
                "{}",
                match *self {
                    RouilleBincodeError::BodyAlreadyExtracted => {
                        "the body of the request was already extracted"
                    }
                    RouilleBincodeError::WrongContentType => {
                        "the request didn't have a binary content type"
                    }
                    RouilleBincodeError::ParseError(_) => "error while parsing the bincode body",
                }
            )
        }
    }
    fn bincode_input<O>(request: &rouille::Request) -> std::result::Result<O, RouilleBincodeError>
    where
        O: serde::de::DeserializeOwned,
    {
        if let Some(header) = request.header("Content-Type") {
            if !header.starts_with("application/octet-stream") {
                return Err(RouilleBincodeError::WrongContentType);
            }
        } else {
            return Err(RouilleBincodeError::WrongContentType);
        }

        if let Some(mut b) = request.data() {
            bincode::deserialize_from::<_, O>(&mut b).map_err(From::from)
        } else {
            Err(RouilleBincodeError::BodyAlreadyExtracted)
        }
    }

    // Based on try_or_400 in rouille, but with logging
    #[derive(Serialize)]
    pub struct ErrJson {
        description: String,
        cause: Option<Box<ErrJson>>,
    }

    impl ErrJson {
        fn from_err<E: ?Sized + std::error::Error>(err: &E) -> ErrJson {
            let cause = err.source().map(ErrJson::from_err).map(Box::new);
            ErrJson {
                description: err.to_string(),
                cause,
            }
        }

        fn into_data(self) -> String {
            serde_json::to_string(&self).expect("infallible serialization for ErrJson failed")
        }
    }
    macro_rules! try_or_err_and_log {
        ($reqid:expr, $code:expr, $result:expr) => {
            match $result {
                Ok(r) => r,
                Err(err) => {
                    // TODO: would ideally just use error_chain
                    #[allow(unused_imports)]
                    use std::error::Error;
                    let mut err_msg = err.to_string();
                    let mut maybe_cause = err.source();
                    while let Some(cause) = maybe_cause {
                        err_msg.push_str(", caused by: ");
                        err_msg.push_str(&cause.to_string());
                        maybe_cause = cause.source();
                    }

                    warn!("Res {} error: {}", $reqid, err_msg);
                    let err: Box<dyn std::error::Error + 'static> = err.into();
                    let json = ErrJson::from_err(&*err);
                    return rouille::Response::json(&json).with_status_code($code);
                }
            }
        };
    }
    macro_rules! try_or_400_log {
        ($reqid:expr, $result:expr) => {
            try_or_err_and_log!($reqid, 400, $result)
        };
    }
    macro_rules! try_or_500_log {
        ($reqid:expr, $result:expr) => {
            try_or_err_and_log!($reqid, 500, $result)
        };
    }
    fn make_401_with_body(short_err: &str, body: ClientVisibleMsg) -> rouille::Response {
        rouille::Response {
            status_code: 401,
            headers: vec![(
                "WWW-Authenticate".into(),
                format!("Bearer error=\"{}\"", short_err).into(),
            )],
            data: rouille::ResponseBody::from_data(body.0),
            upgrade: None,
        }
    }
    fn make_401(short_err: &str) -> rouille::Response {
        make_401_with_body(short_err, ClientVisibleMsg(String::new()))
    }
    fn bearer_http_auth(request: &rouille::Request) -> Option<&str> {
        let header = request.header("Authorization")?;

        let mut split = header.splitn(2, |c| c == ' ');

        let authtype = split.next()?;
        if authtype != "Bearer" {
            return None;
        }

        split.next()
    }

    /// Return `content` as a bincode-encoded `Response`.
    pub fn bincode_response<T>(content: &T) -> rouille::Response
    where
        T: serde::Serialize,
    {
        let data = bincode::serialize(content).context("Failed to serialize response body");
        let data = try_or_500_log!("bincode body serialization", data);

        rouille::Response {
            status_code: 200,
            headers: vec![("Content-Type".into(), "application/octet-stream".into())],
            data: rouille::ResponseBody::from_data(data),
            upgrade: None,
        }
    }

    /// Return `content` as either a bincode or json encoded `Response`
    /// depending on the Accept header in `request`.
    pub fn prepare_response<T>(request: &rouille::Request, content: &T) -> rouille::Response
    where
        T: serde::Serialize,
    {
        accept!(request,
        "application/octet-stream" => bincode_response(content),
        "application/json" => rouille::Response::json(content),
        )
    }

    // Verification of job auth in a request
    macro_rules! job_auth_or_401 {
        ($request:ident, $job_authorizer:expr, $job_id:expr) => {{
            let verify_result = match bearer_http_auth($request) {
                Some(token) => $job_authorizer.verify_token($job_id, token),
                None => Err(anyhow!("no Authorization header")),
            };
            match verify_result {
                Ok(()) => (),
                Err(err) => {
                    let err: Box<dyn std::error::Error> = err.into();
                    let json = ErrJson::from_err(&*err);
                    return make_401_with_body("invalid_jwt", ClientVisibleMsg(json.into_data()));
                }
            }
        }};
    }
    // Generation and verification of job auth
    struct JWTJobAuthorizer {
        server_key: Vec<u8>,
    }
    impl JWTJobAuthorizer {
        fn new(server_key: Vec<u8>) -> Box<Self> {
            Box::new(Self { server_key })
        }
    }
    impl dist::JobAuthorizer for JWTJobAuthorizer {
        fn generate_token(&self, job_id: JobId) -> Result<String> {
            let claims = JobJwt { job_id };
            let key = jwt::EncodingKey::from_secret(&self.server_key);
            jwt::encode(&JWT_HEADER, &claims, &key)
                .map_err(|e| anyhow!("Failed to create JWT for job: {}", e))
        }
        fn verify_token(&self, job_id: JobId, token: &str) -> Result<()> {
            let valid_claims = JobJwt { job_id };
            let key = jwt::DecodingKey::from_secret(&self.server_key);
            jwt::decode(&token, &key, &JWT_VALIDATION)
                .map_err(|e| anyhow!("JWT decode failed: {}", e))
                .and_then(|res| {
                    fn identical_t<T>(_: &T, _: &T) {}
                    identical_t(&res.claims, &valid_claims);
                    if res.claims == valid_claims {
                        Ok(())
                    } else {
                        Err(anyhow!("mismatched claims"))
                    }
                })
        }
    }

    #[test]
    fn test_job_token_verification() {
        let ja = JWTJobAuthorizer::new(vec![1, 2, 2]);

        let job_id = JobId(55);
        let token = ja.generate_token(job_id).unwrap();

        let job_id2 = JobId(56);
        let token2 = ja.generate_token(job_id2).unwrap();

        let ja2 = JWTJobAuthorizer::new(vec![1, 2, 3]);

        // Check tokens are deterministic
        assert_eq!(token, ja.generate_token(job_id).unwrap());
        // Check token verification works
        assert!(ja.verify_token(job_id, &token).is_ok());
        assert!(ja.verify_token(job_id, &token2).is_err());
        assert!(ja.verify_token(job_id2, &token).is_err());
        assert!(ja.verify_token(job_id2, &token2).is_ok());
        // Check token verification with a different key fails
        assert!(ja2.verify_token(job_id, &token).is_err());
        assert!(ja2.verify_token(job_id2, &token2).is_err());
    }

    pub struct Scheduler<S> {
        public_addr: SocketAddr,
        handler: S,
        // Is this client permitted to use the scheduler?
        check_client_auth: Box<dyn ClientAuthCheck>,
        // Do we believe the server is who they appear to be?
        check_server_auth: ServerAuthCheck,
    }

    impl<S: dist::SchedulerIncoming + 'static> Scheduler<S> {
        pub fn new(
            public_addr: SocketAddr,
            handler: S,
            check_client_auth: Box<dyn ClientAuthCheck>,
            check_server_auth: ServerAuthCheck,
        ) -> Self {
            Self {
                public_addr,
                handler,
                check_client_auth,
                check_server_auth,
            }
        }

        pub fn start(self) -> Result<Void> {
            let Self {
                public_addr,
                handler,
                check_client_auth,
                check_server_auth,
            } = self;
            let requester = SchedulerRequester {
                client: Mutex::new(reqwest::blocking::Client::new()),
            };

            macro_rules! check_server_auth_or_err {
                ($request:ident) => {{
                    match bearer_http_auth($request).and_then(&*check_server_auth) {
                        Some(server_id) => {
                            let origin_ip = if let Some(header_val) = $request.header("X-Real-IP") {
                                trace!("X-Real-IP: {:?}", header_val);
                                match header_val.parse() {
                                    Ok(ip) => ip,
                                    Err(err) => {
                                        warn!(
                                            "X-Real-IP value {:?} could not be parsed: {:?}",
                                            header_val, err
                                        );
                                        return rouille::Response::empty_400();
                                    }
                                }
                            } else {
                                $request.remote_addr().ip()
                            };
                            if server_id.addr().ip() != origin_ip {
                                trace!("server ip: {:?}", server_id.addr().ip());
                                trace!("request ip: {:?}", $request.remote_addr().ip());
                                return make_401("invalid_bearer_token_mismatched_address");
                            } else {
                                server_id
                            }
                        }
                        None => return make_401("invalid_bearer_token"),
                    }
                }};
            }

            fn maybe_update_certs(
                client: &mut reqwest::blocking::Client,
                certs: &mut HashMap<ServerId, (Vec<u8>, Vec<u8>)>,
                server_id: ServerId,
                cert_digest: Vec<u8>,
                cert_pem: Vec<u8>,
            ) -> Result<()> {
                if let Some((saved_cert_digest, _)) = certs.get(&server_id) {
                    if saved_cert_digest == &cert_digest {
                        return Ok(());
                    }
                }
                info!(
                    "Adding new certificate for {} to scheduler",
                    server_id.addr()
                );
                let mut client_builder = reqwest::blocking::ClientBuilder::new();
                // Add all the certificates we know about
                client_builder = client_builder.add_root_certificate(
                    reqwest::Certificate::from_pem(&cert_pem)
                        .context("failed to interpret pem as certificate")?,
                );
                for (_, cert_pem) in certs.values() {
                    client_builder = client_builder.add_root_certificate(
                        reqwest::Certificate::from_pem(cert_pem).expect("previously valid cert"),
                    );
                }
                // Finish the clients
                let new_client = client_builder
                    .build()
                    .context("failed to create a HTTP client")?;
                // Use the updated certificates
                *client = new_client;
                certs.insert(server_id, (cert_digest, cert_pem));
                Ok(())
            }

            info!("Scheduler listening for clients on {}", public_addr);
            let request_count = atomic::AtomicUsize::new(0);
            // From server_id -> cert_digest, cert_pem
            let server_certificates: Mutex<HashMap<ServerId, (Vec<u8>, Vec<u8>)>> =
                Default::default();

            let server = rouille::Server::new(public_addr, move |request| {
                let req_id = request_count.fetch_add(1, atomic::Ordering::SeqCst);
                trace!("Req {} ({}): {:?}", req_id, request.remote_addr(), request);
                let response = (|| router!(request,
                    (POST) (/api/v1/scheduler/alloc_job) => {
                        let bearer_auth = match bearer_http_auth(request) {
                            Some(s) => s,
                            None => return make_401("no_bearer_auth"),
                        };
                        match check_client_auth.check(bearer_auth) {
                            Ok(()) => (),
                            Err(client_msg) => {
                                warn!("Bearer auth failed: {:?}", client_msg);
                                return make_401_with_body("bearer_auth_failed", client_msg)
                            },
                        }
                        let toolchain = try_or_400_log!(req_id, bincode_input(request));
                        trace!("Req {}: alloc_job: {:?}", req_id, toolchain);

                        let alloc_job_res: AllocJobResult = try_or_500_log!(req_id, handler.handle_alloc_job(&requester, toolchain));
                        let certs = server_certificates.lock().unwrap();
                        let res = AllocJobHttpResponse::from_alloc_job_result(alloc_job_res, &certs);
                        prepare_response(&request, &res)
                    },
                    (GET) (/api/v1/scheduler/server_certificate/{server_id: ServerId}) => {
                        let certs = server_certificates.lock().unwrap();
                        let (cert_digest, cert_pem) = try_or_500_log!(req_id, certs.get(&server_id)
                            .context("server cert not available"));
                        let res = ServerCertificateHttpResponse {
                            cert_digest: cert_digest.clone(),
                            cert_pem: cert_pem.clone(),
                        };
                        prepare_response(&request, &res)
                    },
                    (POST) (/api/v1/scheduler/heartbeat_server) => {
                        let server_id = check_server_auth_or_err!(request);
                        let heartbeat_server = try_or_400_log!(req_id, bincode_input(request));
                        trace!("Req {}: heartbeat_server: {:?}", req_id, heartbeat_server);

                        let HeartbeatServerHttpRequest { num_cpus, jwt_key, server_nonce, cert_digest, cert_pem } = heartbeat_server;
                        try_or_500_log!(req_id, maybe_update_certs(
                            &mut requester.client.lock().unwrap(),
                            &mut server_certificates.lock().unwrap(),
                            server_id, cert_digest, cert_pem
                        ));
                        let job_authorizer = JWTJobAuthorizer::new(jwt_key);
                        let res: HeartbeatServerResult = try_or_500_log!(req_id, handler.handle_heartbeat_server(
                            server_id, server_nonce,
                            num_cpus,
                            job_authorizer
                        ));
                        prepare_response(&request, &res)
                    },
                    (POST) (/api/v1/scheduler/job_state/{job_id: JobId}) => {
                        let server_id = check_server_auth_or_err!(request);
                        let job_state = try_or_400_log!(req_id, bincode_input(request));
                        trace!("Req {}: job state: {:?}", req_id, job_state);

                        let res: UpdateJobStateResult = try_or_500_log!(req_id, handler.handle_update_job_state(
                            job_id, server_id, job_state
                        ));
                        prepare_response(&request, &res)
                    },
                    (GET) (/api/v1/scheduler/status) => {
                        let res: SchedulerStatusResult = try_or_500_log!(req_id, handler.handle_status());
                        prepare_response(&request, &res)
                    },
                    _ => {
                        warn!("Unknown request {:?}", request);
                        rouille::Response::empty_404()
                    },
                ))();
                trace!("Res {}: {:?}", req_id, response);
                response
            }).map_err(|e| anyhow!(format!("Failed to start http server for sccache scheduler: {}", e)))?;

            // This limit is rouille's default for `start_server_with_pool`, which
            // we would use, except that interface doesn't permit any sort of
            // error handling to be done.
            let server = server.pool_size(num_cpus::get() * 8);
            server.run();

            panic!("Rouille server terminated")
        }
    }

    struct SchedulerRequester {
        client: Mutex<reqwest::blocking::Client>,
    }

    impl dist::SchedulerOutgoing for SchedulerRequester {
        fn do_assign_job(
            &self,
            server_id: ServerId,
            job_id: JobId,
            tc: Toolchain,
            auth: String,
        ) -> Result<AssignJobResult> {
            let url = urls::server_assign_job(server_id, job_id);
            let req = self.client.lock().unwrap().post(url);
            bincode_req(req.bearer_auth(auth).bincode(&tc)?)
                .context("POST to scheduler assign_job failed")
        }
    }

    pub struct Server<S> {
        public_addr: SocketAddr,
        scheduler_url: reqwest::Url,
        scheduler_auth: String,
        // HTTPS pieces all the builders will use for connection encryption
        cert_digest: Vec<u8>,
        cert_pem: Vec<u8>,
        privkey_pem: Vec<u8>,
        // Key used to sign any requests relating to jobs
        jwt_key: Vec<u8>,
        // Randomly generated nonce to allow the scheduler to detect server restarts
        server_nonce: ServerNonce,
        handler: S,
    }

    impl<S: dist::ServerIncoming + 'static> Server<S> {
        pub fn new(
            public_addr: SocketAddr,
            scheduler_url: reqwest::Url,
            scheduler_auth: String,
            handler: S,
        ) -> Result<Self> {
            let (cert_digest, cert_pem, privkey_pem) =
                create_https_cert_and_privkey(public_addr)
                    .context("failed to create HTTPS certificate for server")?;
            let mut jwt_key = vec![0; JWT_KEY_LENGTH];
            OsRng.fill_bytes(&mut jwt_key);
            let server_nonce = ServerNonce::new();

            Ok(Self {
                public_addr,
                scheduler_url,
                scheduler_auth,
                cert_digest,
                cert_pem,
                privkey_pem,
                jwt_key,
                server_nonce,
                handler,
            })
        }

        pub fn start(self) -> Result<Void> {
            let Self {
                public_addr,
                scheduler_url,
                scheduler_auth,
                cert_digest,
                cert_pem,
                privkey_pem,
                jwt_key,
                server_nonce,
                handler,
            } = self;
            let heartbeat_req = HeartbeatServerHttpRequest {
                num_cpus: num_cpus::get(),
                jwt_key: jwt_key.clone(),
                server_nonce,
                cert_digest,
                cert_pem: cert_pem.clone(),
            };
            let job_authorizer = JWTJobAuthorizer::new(jwt_key);
            let heartbeat_url = urls::scheduler_heartbeat_server(&scheduler_url);
            let requester = ServerRequester {
                client: reqwest::blocking::Client::new(),
                scheduler_url,
                scheduler_auth: scheduler_auth.clone(),
            };

            // TODO: detect if this panics
            thread::spawn(move || {
                let client = reqwest::blocking::Client::new();
                loop {
                    trace!("Performing heartbeat");
                    match bincode_req(
                        client
                            .post(heartbeat_url.clone())
                            .bearer_auth(scheduler_auth.clone())
                            .bincode(&heartbeat_req)
                            .expect("failed to serialize heartbeat"),
                    ) {
                        Ok(HeartbeatServerResult { is_new }) => {
                            trace!("Heartbeat success is_new={}", is_new);
                            // TODO: if is_new, terminate all running jobs
                            thread::sleep(HEARTBEAT_INTERVAL)
                        }
                        Err(e) => {
                            error!("Failed to send heartbeat to server: {}", e);
                            thread::sleep(HEARTBEAT_ERROR_INTERVAL)
                        }
                    }
                }
            });

            info!("Server listening for clients on {}", public_addr);
            let request_count = atomic::AtomicUsize::new(0);

            let server = rouille::Server::new_ssl(public_addr, move |request| {
                let req_id = request_count.fetch_add(1, atomic::Ordering::SeqCst);
                trace!("Req {} ({}): {:?}", req_id, request.remote_addr(), request);
                let response = (|| router!(request,
                    (POST) (/api/v1/distserver/assign_job/{job_id: JobId}) => {
                        job_auth_or_401!(request, &job_authorizer, job_id);
                        let toolchain = try_or_400_log!(req_id, bincode_input(request));
                        trace!("Req {}: assign_job({}): {:?}", req_id, job_id, toolchain);

                        let res: AssignJobResult = try_or_500_log!(req_id, handler.handle_assign_job(job_id, toolchain));
                        prepare_response(&request, &res)
                    },
                    (POST) (/api/v1/distserver/submit_toolchain/{job_id: JobId}) => {
                        job_auth_or_401!(request, &job_authorizer, job_id);
                        trace!("Req {}: submit_toolchain({})", req_id, job_id);

                        let body = request.data().expect("body was already read in submit_toolchain");
                        let toolchain_rdr = ToolchainReader(Box::new(body));
                        let res: SubmitToolchainResult = try_or_500_log!(req_id, handler.handle_submit_toolchain(&requester, job_id, toolchain_rdr));
                        prepare_response(&request, &res)
                    },
                    (POST) (/api/v1/distserver/run_job/{job_id: JobId}) => {
                        job_auth_or_401!(request, &job_authorizer, job_id);

                        let mut body = request.data().expect("body was already read in run_job");
                        let bincode_length = try_or_500_log!(req_id, body.read_u32::<BigEndian>()
                            .context("failed to read run job input length")) as u64;

                        let mut bincode_reader = body.take(bincode_length);
                        let runjob = try_or_500_log!(req_id, bincode::deserialize_from(&mut bincode_reader)
                            .context("failed to deserialize run job request"));
                        trace!("Req {}: run_job({}): {:?}", req_id, job_id, runjob);
                        let RunJobHttpRequest { command, outputs } = runjob;
                        let body = bincode_reader.into_inner();
                        let inputs_rdr = InputsReader(Box::new(ZlibReadDecoder::new(body)));
                        let outputs = outputs.into_iter().collect();

                        let res: RunJobResult = try_or_500_log!(req_id, handler.handle_run_job(&requester, job_id, command, outputs, inputs_rdr));
                        prepare_response(&request, &res)
                    },
                    _ => {
                        warn!("Unknown request {:?}", request);
                        rouille::Response::empty_404()
                    },
                ))();
                trace!("Res {}: {:?}", req_id, response);
                response
            }, cert_pem, privkey_pem).map_err(|e| anyhow!(format!("Failed to start http server for sccache server: {}", e)))?;

            // This limit is rouille's default for `start_server_with_pool`, which
            // we would use, except that interface doesn't permit any sort of
            // error handling to be done.
            let server = server.pool_size(num_cpus::get() * 8);
            server.run();

            panic!("Rouille server terminated")
        }
    }

    struct ServerRequester {
        client: reqwest::blocking::Client,
        scheduler_url: reqwest::Url,
        scheduler_auth: String,
    }

    impl dist::ServerOutgoing for ServerRequester {
        fn do_update_job_state(
            &self,
            job_id: JobId,
            state: JobState,
        ) -> Result<UpdateJobStateResult> {
            let url = urls::scheduler_job_state(&self.scheduler_url, job_id);
            bincode_req(
                self.client
                    .post(url)
                    .bearer_auth(self.scheduler_auth.clone())
                    .bincode(&state)?,
            )
            .context("POST to scheduler job_state failed")
        }
    }
}

#[cfg(feature = "dist-client")]
mod client {
    use super::super::cache;
    use crate::config;
    use crate::dist::pkg::{InputsPackager, ToolchainPackager};
    use crate::dist::{
        self, AllocJobResult, CompileCommand, JobAlloc, PathTransformer, RunJobResult,
        SchedulerStatusResult, SubmitToolchainResult, Toolchain,
    };

    use byteorder::{BigEndian, WriteBytesExt};
    use flate2::write::ZlibEncoder as ZlibWriteEncoder;
    use flate2::Compression;
    use std::collections::HashMap;
    use std::io::Write;
    use std::path::{Path, PathBuf};
    use std::sync::{Arc, Mutex};
    use std::time::Duration;

    use super::common::{
        bincode_req, bincode_req_fut, AllocJobHttpResponse, ReqwestRequestBuilderExt,
        RunJobHttpRequest, ServerCertificateHttpResponse,
    };
    use super::urls;
    use crate::errors::*;

    const REQUEST_TIMEOUT_SECS: u64 = 600;
    const CONNECT_TIMEOUT_SECS: u64 = 5;

    pub struct Client {
        auth_token: String,
        scheduler_url: reqwest::Url,
        // cert_digest -> cert_pem
        server_certs: Arc<Mutex<HashMap<Vec<u8>, Vec<u8>>>>,
        // TODO: this should really only use the async client, but reqwest async bodies are extremely limited
        // and only support owned bytes, which means the whole toolchain would end up in memory
        client: Arc<Mutex<reqwest::blocking::Client>>,
        client_async: Arc<Mutex<reqwest::Client>>,
        pool: tokio::runtime::Handle,
        tc_cache: Arc<cache::ClientToolchains>,
        rewrite_includes_only: bool,
    }

    impl Client {
        pub fn new(
            pool: &tokio::runtime::Handle,
            scheduler_url: reqwest::Url,
            cache_dir: &Path,
            cache_size: u64,
            toolchain_configs: &[config::DistToolchainConfig],
            auth_token: String,
            rewrite_includes_only: bool,
        ) -> Result<Self> {
            let timeout = Duration::new(REQUEST_TIMEOUT_SECS, 0);
            let connect_timeout = Duration::new(CONNECT_TIMEOUT_SECS, 0);
            let client = reqwest::blocking::ClientBuilder::new()
                .timeout(timeout)
                .connect_timeout(connect_timeout)
                .build()
                .context("failed to create a HTTP client")?;
            let client_async = reqwest::ClientBuilder::new()
                .timeout(timeout)
                .connect_timeout(connect_timeout)
                .build()
                .context("failed to create an async HTTP client")?;
            let client_toolchains =
                cache::ClientToolchains::new(cache_dir, cache_size, toolchain_configs)
                    .context("failed to initialise client toolchains")?;
            Ok(Self {
                auth_token,
                scheduler_url,
                server_certs: Default::default(),
                client: Arc::new(Mutex::new(client)),
                client_async: Arc::new(Mutex::new(client_async)),
                pool: pool.clone(),
                tc_cache: Arc::new(client_toolchains),
                rewrite_includes_only,
            })
        }

        fn update_certs(
            client: &mut reqwest::blocking::Client,
            client_async: &mut reqwest::Client,
            certs: &mut HashMap<Vec<u8>, Vec<u8>>,
            cert_digest: Vec<u8>,
            cert_pem: Vec<u8>,
        ) -> Result<()> {
            let mut client_builder = reqwest::blocking::ClientBuilder::new();
            let mut client_async_builder = reqwest::ClientBuilder::new();
            // Add all the certificates we know about
            client_builder = client_builder.add_root_certificate(
                reqwest::Certificate::from_pem(&cert_pem)
                    .context("failed to interpret pem as certificate")?,
            );
            client_async_builder = client_async_builder.add_root_certificate(
                reqwest::Certificate::from_pem(&cert_pem)
                    .context("failed to interpret pem as certificate")?,
            );
            for cert_pem in certs.values() {
                client_builder = client_builder.add_root_certificate(
                    reqwest::Certificate::from_pem(cert_pem).expect("previously valid cert"),
                );
                client_async_builder = client_async_builder.add_root_certificate(
                    reqwest::Certificate::from_pem(cert_pem).expect("previously valid cert"),
                );
            }
            // Finish the clients
            let timeout = Duration::new(REQUEST_TIMEOUT_SECS, 0);
            let new_client = client_builder
                .timeout(timeout)
                .build()
                .context("failed to create a HTTP client")?;
            let new_client_async = client_async_builder
                .timeout(timeout)
                .build()
                .context("failed to create an async HTTP client")?;
            // Use the updated certificates
            *client = new_client;
            *client_async = new_client_async;
            certs.insert(cert_digest, cert_pem);
            Ok(())
        }
    }

    #[async_trait]
    impl dist::Client for Client {
        async fn do_alloc_job(&self, tc: Toolchain) -> Result<AllocJobResult> {
            let scheduler_url = self.scheduler_url.clone();
            let url = urls::scheduler_alloc_job(&scheduler_url);
            let mut req = self.client_async.lock().unwrap().post(url);
            req = req.bearer_auth(self.auth_token.clone()).bincode(&tc)?;

            let client = self.client.clone();
            let client_async = self.client_async.clone();
            let server_certs = self.server_certs.clone();

            match bincode_req_fut(req).await? {
                AllocJobHttpResponse::Success {
                    job_alloc,
                    need_toolchain,
                    cert_digest,
                } => {
                    let server_id = job_alloc.server_id;
                    let alloc_job_res = Ok(AllocJobResult::Success {
                        job_alloc,
                        need_toolchain,
                    });
                    if server_certs.lock().unwrap().contains_key(&cert_digest) {
                        return alloc_job_res;
                    }
                    info!(
                        "Need to request new certificate for server {}",
                        server_id.addr()
                    );
                    let url = urls::scheduler_server_certificate(&scheduler_url, server_id);
                    let req = client_async.lock().unwrap().get(url);
                    let res: ServerCertificateHttpResponse = bincode_req_fut(req)
                        .await
                        .context("GET to scheduler server_certificate failed")?;

                    // TODO: Move to asynchronous reqwest client only.
                    // This function internally builds a blocking reqwest client;
                    // However, it does so by utilizing a runtime which it drops,
                    // triggering (rightfully) a sanity check that prevents from
                    // dropping a runtime in asynchronous context.
                    // For the time being, we work around this by off-loading it
                    // to a dedicated blocking-friendly thread pool.
                    let _ = self
                        .pool
                        .spawn_blocking(move || {
                            Self::update_certs(
                                &mut client.lock().unwrap(),
                                &mut client_async.lock().unwrap(),
                                &mut server_certs.lock().unwrap(),
                                res.cert_digest,
                                res.cert_pem,
                            )
                            .context("Failed to update certificate")
                            .unwrap_or_else(|e| warn!("Failed to update certificate: {:?}", e));
                        })
                        .await;

                    alloc_job_res
                }
                AllocJobHttpResponse::Fail { msg } => Ok(AllocJobResult::Fail { msg }),
            }
        }

        async fn do_get_status(&self) -> Result<SchedulerStatusResult> {
            let scheduler_url = self.scheduler_url.clone();
            let url = urls::scheduler_status(&scheduler_url);
            let req = self.client.lock().unwrap().get(url);

            self.pool.spawn_blocking(move || bincode_req(req)).await?
        }

        async fn do_submit_toolchain(
            &self,
            job_alloc: JobAlloc,
            tc: Toolchain,
        ) -> Result<SubmitToolchainResult> {
            match self.tc_cache.get_toolchain(&tc) {
                Ok(Some(toolchain_file)) => {
                    let url = urls::server_submit_toolchain(job_alloc.server_id, job_alloc.job_id);
                    let req = self.client.lock().unwrap().post(url);
                    self.pool
                        .spawn_blocking(move || {
                            let toolchain_file_size = toolchain_file.metadata()?.len();
                            let body =
                                reqwest::blocking::Body::sized(toolchain_file, toolchain_file_size);
                            let req = req.bearer_auth(job_alloc.auth).body(body);
                            bincode_req(req)
                        })
                        .await?
                }
                Ok(None) => Err(anyhow!("couldn't find toolchain locally")),
                Err(e) => Err(e),
            }
        }

        async fn do_run_job(
            &self,
            job_alloc: JobAlloc,
            command: CompileCommand,
            outputs: Vec<String>,
            inputs_packager: Box<dyn InputsPackager>,
        ) -> Result<(RunJobResult, PathTransformer)> {
            let url = urls::server_run_job(job_alloc.server_id, job_alloc.job_id);
            let mut req = self.client.lock().unwrap().post(url);

            self.pool
                .spawn_blocking(move || {
                    let bincode = bincode::serialize(&RunJobHttpRequest { command, outputs })
                        .context("failed to serialize run job request")?;
                    let bincode_length = bincode.len();

                    let mut body = vec![];
                    body.write_u32::<BigEndian>(bincode_length as u32)
                        .expect("Infallible write of bincode length to vec failed");
                    body.write_all(&bincode)
                        .expect("Infallible write of bincode body to vec failed");
                    let path_transformer;
                    {
                        let mut compressor = ZlibWriteEncoder::new(&mut body, Compression::fast());
                        path_transformer = inputs_packager
                            .write_inputs(&mut compressor)
                            .context("Could not write inputs for compilation")?;
                        compressor.flush().context("failed to flush compressor")?;
                        trace!(
                            "Compressed inputs from {} -> {}",
                            compressor.total_in(),
                            compressor.total_out()
                        );
                        compressor.finish().context("failed to finish compressor")?;
                    }

                    req = req.bearer_auth(job_alloc.auth.clone()).bytes(body);
                    bincode_req(req).map(|res| (res, path_transformer))
                })
                .await?
        }

        async fn put_toolchain(
            &self,
            compiler_path: PathBuf,
            weak_key: String,
            toolchain_packager: Box<dyn ToolchainPackager>,
        ) -> Result<(Toolchain, Option<(String, PathBuf)>)> {
            let compiler_path = compiler_path.to_owned();
            let weak_key = weak_key.to_owned();
            let tc_cache = self.tc_cache.clone();

            self.pool
                .spawn_blocking(move || {
                    tc_cache.put_toolchain(&compiler_path, &weak_key, toolchain_packager)
                })
                .await?
        }

        fn rewrite_includes_only(&self) -> bool {
            self.rewrite_includes_only
        }
        fn get_custom_toolchain(&self, exe: &Path) -> Option<PathBuf> {
            match self.tc_cache.get_custom_toolchain(exe) {
                Some(Ok((_, _, path))) => Some(path),
                _ => None,
            }
        }
    }
}


text:
from setuptools import setup

options = {
  'name': 'python-dbase',
  'version': '0.1',
  'description': 'Python dbase operations module',
  'url': 'https://github.com/python-dbase/python-dbase',
  'author': 'David Kwast',
  'author_email': 'david@kwast.net',
  'license': 'MIT',
  'packages': ['dbase'],
  'zip_safe': False
}

setup(**options)


text:
//
//  HBSTableViewFactory.h
//  Pods
//
//  Created by Anokhov Pavel on 28.02.16.
//
//

@import UIKit;

NS_ASSUME_NONNULL_BEGIN

@protocol HBSTableViewFactory <NSObject>

@required
#pragma mark Providing Cells and headers
/** This method called when tableView requests a cell. You should only dequeue cell here, perform basic setup if needed, and return it. */
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath withObject:(nullable id)object inSection:(nullable NSString *)sectionName;
/** This methos called when tableView's willDisplayCell method, AND when fetchedRequestController updates object. You should perform all cell configurations and setups here, like labels and images. */
- (void)configureCell:(UITableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath withObject:(nullable id)object inSection:(nullable NSString *)sectionName;

@optional
/** You can use this method to prepare tableView with [tableView registerClass/Nib:] methods. */
- (void)registerReusablesForTableView:(UITableView*)tableView;

#pragma mark Header and Footer views
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(nullable NSString *)sectionName;
- (UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(nullable NSString *)sectionName;
- (void)configureHeader:(UIView *)header forSection:(nullable NSString *)sectionName;
- (void)configureFooter:(UIView *)footer forSection:(nullable NSString *)sectionName;
- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(nullable NSString *)sectionName;
- (NSString*)tableView:(UITableView *)tableView titleForFooterInSection:(nullable NSString *)sectionName;

#pragma mark Row, Header and Footer heights
- (CGFloat)tableView:(UITableView *)tableView heightForRow:(NSIndexPath *)indexPath inSection:(nullable NSString *)sectionName;
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(nullable NSString *)sectionName;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(nullable NSString *)sectionName;
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRow:(NSIndexPath *)indexPath inSection:(nullable NSString *)sectionName;
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(nullable NSString *)sectionName;
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(nullable NSString *)sectionName;

@end

NS_ASSUME_NONNULL_END


text:
title: Setting up networked photo frame with Raspberry Pi
tags: raspberrypi, photography
---

Having set up audio streaming with my RPi that was collecting dust (since my last post :),
I ended up with a left-over RPi Zero W. And we finally decided to showcase all family photos, perfect timing!
Setting up a networked photo frame has a couple of quirks to it...

<!--break-->
## The plan
The idea is to show _all_ pictures from a network file share, and have non-interactive slideshow
running from RPi & connected HDMI monitor

## Network share
I am using my always-on windows machine - I have set up separate user just for this purpose and shared the folder.
As optimization step, I also made a list of all jpeg files in the folder - as enumerating them over the network takes time.
This command dumps and shuffles the list (I am running this in the WSL console):
```
find . -name "*.jpg" | shuf --output images.txt
```

## RPi setup

### Distro
There are several tools that can display slideshows - some work using framebuffer (so no X windows required).
I have been experimenting with them all and so far stopped at `feh` - it runs under X, so I installed full Raspbian distribution,
which conviniently auto-logs you in.

### RPi config
* Using raspi-config, enable SSH so you can configure the frame remotely (it's under Interfacing options)
* Also under Interfacing options enable VNC, so you can see what's going on remotely and control the terminal attached to graphical console.
(you can do that from ssh, but this is more straightforward)
* If you already connected your screen and see black border, go to Advanced options and enable Overscan
* Under Boot options enable "Wait for Network to boot" - we'll need this later to auto-mount network share
* Enable auto login - go to Boot Options, and in "B1 Desktop / CLI" pick  "B4 Desktop Autologin"

### Mounting network share
There are couple of steps here - first test that you can mount your network share you set up:

Set up folder where you will be mounting, for example:
```
mkdir /mnt/photos
```

Test that you can mount:
```
sudo mount -t cifs -o username=share,noserverino //192.168.11.102/Photos /mnt/photos
```

What are the options here:
* cifs - this is windows file sharing, or samba, protocol. Note that if you want to use NFS, you put NFS here.
* username=share - that's the user I set up on my server, yours can be different
* noserverino - super duper important option - if your server has >1TB disk, you'll have crashes with all the slide
show tools I mentioned, as on 32 bit RPi they are not compiled to support this size.
* the IP address - since RPi doesn't really participate in network discovery, I fixed the IP of my server
(in windows you go and assign IP address manually)
* /mnt/photos - that's where your photos will show up

When you run the command above it will ask you for password - type it in, and you should see your photos in /mnt/photos

### Automatically mounting
We want the RPi to restart unattended, so let's set this up:
```
sudo vi /etc/fstab
```

This file contains the partitions to mount at startup, so let's add ours here.
The options from mount command also go into this file:

```//192.168.11.102/Photos /mnt/photos     cifs    username=share,noserverino,credentials=/home/pi/.smpasswd       0       0```

(that's tabs between the parameters)

You'll have to make the file /home/pi/.smpasswd, that's what i have there:
```
username=share
password=somepassword
```

If you are worred about someone logging into your photo frame and stealing this password you can store it elsewhere and
only give root access - I just made special user in windows that can only see photos, so no worry.

Restart, and you should see your /mnt/photos populated with pictures - if not, check dmesg.
Remember to enable this "wait for network to boot" option i mentioned before!

## Show the pictures!
As I mentioned before, I tried different tools - fbi, fim, eos and feh. The one that can accept list of files and has auto rotation seems to be feh (that's TBD, but this works fine). Here's the command I am using:
```
cd /mnt/photos
cat images.txt | feh --auto-rotate -Y -x -q -D 5 -B black -F -Z -z -r -f -
```

Remember that I made image list on the server before. You can skip this, but I can't -  have 70k images with many subfolders. If you skip this, you can use --recursive option in feh instead.

### Automatically starting slideshow on start
Simply calling the script above is enough when starting RPi (remember that it logs you into X windows automatically). Create this folder structure and file and mention the script with feh command there:
```
mkdir -p ~/.config/lxsession/LXDE-pi
vi ~/.config/lxsession/LXDE-pi/autostart
```

this is all I have in the autostart file:
```
/home/pi/show.sh
```

## Done
At this point you should be able to restart RPi at any time and have slideshow come up.
In case of trouble your diagnostics is dmesg (for mounting folders) and running feh command manually.


text:
/*
 * Created on Feb 20, 2006
 *
 * TODO To change the template for this generated file go to Window - Preferences - Java - Code
 * Style - Code Templates
 */
package org.apache.geode.internal.cache;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.util.Collection;

import org.junit.Test;

import org.apache.geode.internal.cache.entries.DiskEntry;

/**
 * This test does a check that conflation in the buffer happen correctly
 *
 * Conflation cases tested include:
 *

 *
create, modify
 *
create, destroy
 *
create, destroy, create
 *
create, invalidate
 *
create, invalidate
 *
create, invalidate, modify
 *

 * The test is done for persist only, overflow only and persist + overflow only (async modes).
 */
public class ConflationJUnitTest extends DiskRegionTestingBase {

  private DiskRegionProperties diskProps = new DiskRegionProperties();

  private long flushCount;

  @Override
  protected final void postSetUp() throws Exception {
    diskProps.setDiskDirs(dirs);
    diskProps.setBytesThreshold(100000000);
    diskProps.setTimeInterval(100000000);
    diskProps.setSynchronous(false);
  }

  private void createPersistOnly() {
    region = DiskRegionHelperFactory.getAsyncPersistOnlyRegion(cache, diskProps);
  }

  private void createOverflowAndPersist() {
    region = DiskRegionHelperFactory.getAsyncOverFlowAndPersistRegion(cache, diskProps);
  }

  /**
   * do a put followed by a put
   */
  private void putAndPut() {
    region.put(new Integer(1), new Integer(1));
    region.put(new Integer(1), new Integer(2));
  }

  /**
   * do a put followed by a destroy on the same entry
   */
  private void putAndDestroy() {
    region.put(new Integer(1), new Integer(1));
    try {
      region.destroy(new Integer(1));
    } catch (Exception e) {
      logWriter.error("Exception occurred", e);
      fail(" failed to destory Integer");
    }
  }

  /**
   * do a put destroy the same entry and put it again
   */
  private void putDestroyPut() {
    putAndDestroy();
    region.put(new Integer(1), new Integer(2));
  }

  /**
   * put a key and then invalidate it
   */
  private void putAndInvalidate() {
    region.put(new Integer(1), new Integer(1));
    try {
      region.invalidate(new Integer(1));
    } catch (Exception e) {
      logWriter.error("Exception occurred", e);
      throw new AssertionError(" failed to invalidate Integer", e);
    }
  }

  /**
   * put a key, invalidate it and the perform a put on it
   */
  private void putInvalidatePut() {
    putAndInvalidate();
    region.put(new Integer(1), new Integer(2));
  }

  /**
   * do a create and then a put on the same key
   */
  private void createAndPut() {
    try {
      region.create(new Integer(1), new Integer(1));
    } catch (Exception e) {
      logWriter.error("Exception occurred", e);
      throw new AssertionError(" failed in trying to create", e);
    }
    region.put(new Integer(1), new Integer(2));
  }

  /**
   * do a create and then a destroy
   */
  private void createAndDestroy() {
    try {
      region.create(new Integer(1), new Integer(1));
    } catch (Exception e) {
      logWriter.error("Exception occurred", e);
      throw new AssertionError("failed in trying to create", e);
    }
    try {
      region.destroy(new Integer(1));
    } catch (Exception e) {
      logWriter.error("Exception occurred", e);
      throw new AssertionError("failed to destroy Integer", e);
    }
  }

  /**
   * do a create then destroy the entry and create it again
   */
  private void createDestroyCreate() {
    createAndDestroy();
    try {
      region.create(new Integer(1), new Integer(2));
    } catch (Exception e) {
      logWriter.error("Exception occurred", e);
      throw new AssertionError("failed in trying to create", e);
    }
  }

  /**
   * create an entry and then invalidate it
   */
  private void createAndInvalidate() {
    try {
      region.create(new Integer(1), new Integer(1));
    } catch (Exception e) {
      logWriter.error("Exception occurred", e);
      throw new AssertionError("failed in trying to create", e);
    }
    try {
      region.invalidate(new Integer(1));
    } catch (Exception e) {
      logWriter.error("Exception occurred", e);
      throw new AssertionError("failed to invalidate Integer", e);
    }
  }

  /**
   * create an entry, invalidate it and then perform a put on the same key
   */
  private void createInvalidatePut() {
    createAndInvalidate();
    region.put(new Integer(1), new Integer(2));
  }

  /**
   * validate whether a modification of an entry was correctly done
   */
  private void validateModification() {
    Collection entries = ((LocalRegion) region).entries.regionEntries();
    if (entries.size() != 1) {
      fail("expected size to be 1 but is not so");
    }
    RegionEntry entry = (RegionEntry) entries.iterator().next();
    DiskId id = ((DiskEntry) entry).getDiskId();
    Object obj = ((LocalRegion) region).getDiskRegion().get(id);
    if (!(obj.equals(new Integer(2)))) {
      fail("incorrect modification");
    }
  }

  /**
   * validate whether nothing was written
   */
  private void validateNothingWritten() {
    Collection entries = ((LocalRegion) region).entries.regionEntries();
    // We actually will have a tombstone in the region, hence
    // the 1 entry
    if (entries.size() != 1) {
      fail("expected size to be 1 but is " + entries.size());
    }
    assertEquals(this.flushCount, getCurrentFlushCount());
  }

  /**
   * validate whether invalidate was done
   */
  private void validateTombstone() {
    Collection entries = ((LocalRegion) region).entries.regionEntries();
    if (entries.size() != 1) {
      fail("expected size to be 1 but is " + entries.size());
    }
    RegionEntry entry = (RegionEntry) entries.iterator().next();
    DiskId id = ((DiskEntry) entry).getDiskId();
    Object obj = ((LocalRegion) region).getDiskRegion().get(id);
    assertEquals(Token.TOMBSTONE, obj);
  }

  /**
   * validate whether invalidate was done
   */
  private void validateInvalidate() {
    Collection entries = ((LocalRegion) region).entries.regionEntries();
    if (entries.size() != 1) {
      fail("expected size to be 1 but is " + entries.size());
    }
    RegionEntry entry = (RegionEntry) entries.iterator().next();
    DiskId id = ((DiskEntry) entry).getDiskId();
    Object obj = ((LocalRegion) region).getDiskRegion().get(id);
    if (!(obj.equals(Token.INVALID))) {
      fail(" incorrect invalidation");
    }
  }

  private long getCurrentFlushCount() {
    return ((LocalRegion) region).getDiskStore().getStats().getFlushes();
  }

  private void pauseFlush() {
    ((LocalRegion) region).getDiskRegion().pauseFlusherForTesting();
    this.flushCount = getCurrentFlushCount();
  }

  /**
   * force a flush on the region
   */
  private void forceFlush() {
    ((LocalRegion) region).getDiskRegion().flushForTesting();
  }

  /**
   * all the operations done here
   */
  private void allTest() {
    pauseFlush();
    createAndPut();
    forceFlush();
    validateModification();
    region.clear();

    pauseFlush();
    createAndDestroy();
    forceFlush();
    validateTombstone();
    region.clear();

    pauseFlush();
    createAndInvalidate();
    forceFlush();
    validateInvalidate();
    region.clear();

    pauseFlush();
    createDestroyCreate();
    forceFlush();
    validateModification();

    pauseFlush();
    putAndPut();
    forceFlush();
    validateModification();
    region.clear();

    pauseFlush();
    putAndDestroy();
    forceFlush();
    validateTombstone();
    region.clear();

    pauseFlush();
    putAndInvalidate();
    forceFlush();
    validateInvalidate();
    region.clear();
  }

  /**
   * test conflation for perist only
   */
  @Test
  public void testPersistOnlyConflation() throws Exception {
    createPersistOnly();
    allTest();
    closeDown();
  }

  /**
   * test conflation for overflow and persist
   */
  @Test
  public void testOverFlowAndPersistOnlyConflation() throws Exception {
    createOverflowAndPersist();
    allTest();
    closeDown();
  }
}


text:
package com.jameslandrum.bluetoothsmart.actions;

import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;

import com.jameslandrum.bluetoothsmart.Characteristic;
import com.jameslandrum.bluetoothsmart.SmartDevice;
import com.jameslandrum.bluetoothsmart.actions.errors.CharacteristicWriteError;

import org.apache.commons.codec.binary.Hex;

public class SetCharacteristic extends CharacteristicAction implements SmartDevice.GattListener {
	private Characteristic mCharacteristic;
	private byte[] mData;
	private final Object mHolder = new Object();
	private ActionError mError;

	public SetCharacteristic(Characteristic characteristic, byte[] data) {
		super(characteristic);
		mCharacteristic = characteristic;
		mData = data;
	}

	public void refresh(byte[] newValue) {
		mData = newValue;
		super.refresh();
	}

	@Override
	public ActionError execute(SmartDevice smartDevice) {
		mError = super.execute(smartDevice);
		if (mError != null) return mError;

		if (mCharacteristic.getCharacteristic() == null) {
			mError = new Characteristic.CharacteristicNotFoundError();
			return mError;
		}

		BluetoothGattCharacteristic characteristic = mCharacteristic.getCharacteristic();
		characteristic.setValue(mData);

		smartDevice.addGattListener(this);
		mGatt.writeCharacteristic(characteristic);
		characteristic.setValue(mData);
		try { synchronized (mHolder) { mHolder.wait(300); } } catch (InterruptedException e) {
			mError = new CharacteristicWriteError();
		}
		smartDevice.removeGattListener(this);

		if (mCompleteListener != null)
			mCompleteListener.onActionCompleted(this, mError==null);

		return mError;
	}

	public Characteristic getCharacteristic() {
		return mCharacteristic;
	}

	@Override
	public void onCharacteristicWrite(BluetoothGattCharacteristic characteristic, int status) {
		if (status == BluetoothGatt.GATT_FAILURE) {
			mError = new CharacteristicWriteError();
		}
		synchronized (mHolder) {
			mHolder.notify();
		}
	}

	public void enableRepeat(Boolean enable) {
		setRepeating(enable);
	}

	@Override
	public String toString() {
		return "Setting Characteristic " + mCharacteristic.getCharacteristicLabel() + " to " + new String(Hex.encodeHex(mData));
	}

	/* Unused */
	@Override public void onCharacteristicRead(BluetoothGattCharacteristic characteristic, int status) {}
	@Override public void onDescriptorWrite(BluetoothGattDescriptor descriptor, int status) {}
	@Override public void onCharacteristicNotify(Characteristic characteristic) {}

}


text:
McL84scPropagator
=================

About the ``McL84scPropagator`` class
-------------------------------------

.. automodule:: WaveBlocksND

Inheritance diagram
-------------------

.. inheritance-diagram:: McL84scPropagator

Class documentation
-------------------

.. autoclass:: McL84scPropagator
   :members:
   :inherited-members:

   .. automethod:: __init__


text:
<?php

use yii\helpers\StringHelper;

/**
 * This is the template for generating a CRUD controller class file.
 *
 * @var yii\web\View $this
 * @var yii\gii\generators\crud\Generator $generator
 */

$modelClass = StringHelper::basename($generator->modelClass);
$searchModelClass = StringHelper::basename($generator->searchModelClass);
$rules = $generator->generateSearchRules();
$labels = $generator->generateSearchLabels();
$searchAttributes = $generator->getSearchAttributes();
$searchConditions = $generator->generateSearchConditions();

echo "<?php\n";
?>

namespace <?= StringHelper::dirname(ltrim($generator->searchModelClass, '\\')) ?>;

use yii\base\Model;
use yii\data\ActiveDataProvider;
use <?= ltrim($generator->modelClass, '\\') ?>;

/**
 * <?= $searchModelClass ?> represents the model behind the search form about <?= $modelClass ?>.
 */
class <?= $searchModelClass ?> extends Model
{
    // protected $projectId;

	public $<?= implode(";\n\tpublic $", $searchAttributes) ?>;

    /*
    public function __construct($projectId, $config = [])
    {
        parent::__construct($config);

        $this->projectId = $projectId;
    }
    */

	public function rules()
	{
		return [
			<?= implode(",\n\t\t\t", $rules) ?>,
		];
	}

	/**
	 * @inheritdoc
	 */
	public function attributeLabels()
	{
		return [
<?php foreach ($labels as $name => $label): ?>
			<?= "'$name' => '" . addslashes($label) . "',\n" ?>
<?php endforeach; ?>
		];
	}

	public function search($params)
	{
		$query = <?= $modelClass ?>::find();
		$dataProvider = new ActiveDataProvider([
			'query' => $query,
		]);

		if (!($this->load($params) && $this->validate())) {
			return $dataProvider;
		}

		<?= implode("\n\t\t", $searchConditions) ?>

		return $dataProvider;
	}

	protected function addCondition($query, $attribute, $partialMatch = false)
	{
		$value = $this->$attribute;
		if (trim($value) === '') {
			return;
		}
		if ($partialMatch) {
			$value = '%' . strtr($value, ['%'=>'\%', '_'=>'\_', '\\'=>'\\\\']) . '%';
			$query->andWhere(['like', $attribute, $value]);
		} else {
			$query->andWhere([$attribute => $value]);
		}
	}
}


text:
var config = module.exports;

var path = require('path');

// root
config.project_root = path.resolve(process.cwd(), "");
// cache file
config.cache_file = config.project_root + "/oniros.json";
config.cache_struct = {
	"cpts": [],
	"pages": [],
	"taxonomies": []
}

// Templates folder
config.templates_path = path.resolve(__dirname,"templates/wordpress/");

// CPT
config.cpt_template = "/cpt.js";
config.cpt_dist = path.resolve(process.cwd(),"includes/functions/posttypes.php");

// Page Template
config.page_template = "/page-custom.js";

// Category Archive Template
config.cat_template = "/category-cpt.js";

// Taxonomy Archive Template
config.tax_archive_template = "/taxonomy-cpt.js";

// Single CPT
config.single_template = "/single-cpt.js";

// Archive
config.archive_template = "/archive-cpt.js";

// Taxonomy
config.tax_template = "/taxonomy.js";
config.tax_dist = path.resolve(process.cwd(),"includes/functions/taxonomies.php");


text:
package kafka.manager.utils

import kafka.manager.{Kafka_0_8_1_1, ClusterConfig}
import org.scalatest.{Matchers, FunSuite}

/**
 * @author hiral
 */
class TestClusterConfig extends FunSuite with Matchers {

  test("invalid name") {
    intercept[IllegalArgumentException] {
      ClusterConfig("qa!","0.8.1.1","localhost",jmxEnabled = false)
    }
  }

  test("invalid kafka version") {
    intercept[IllegalArgumentException] {
      ClusterConfig("qa","0.8.1","localhost:2181",jmxEnabled = false)
    }
  }

  test("serialize and deserialize") {
    val cc = ClusterConfig("qa","0.8.2.0","localhost:2181", jmxEnabled = true)
    val serialize: String = ClusterConfig.serialize(cc)
    val deserialize = ClusterConfig.deserialize(serialize)
    assert(deserialize.isSuccess === true)
    assert(cc == deserialize.get)
  }

  test("deserialize without version and jmxEnabled") {
    val cc = ClusterConfig("qa","0.8.2.0","localhost:2181", jmxEnabled = false)
    val serialize: String = ClusterConfig.serialize(cc)
    val noverison = serialize.replace(""","kafkaVersion":"0.8.2.0"""","")
    assert(!noverison.contains("kafkaVersion"))
    val deserialize = ClusterConfig.deserialize(noverison)
    assert(deserialize.isSuccess === true)
    assert(cc.copy(version = Kafka_0_8_1_1) == deserialize.get)
  }

  test("deserialize from 0.8.2-beta as 0.8.2.0") {
    val cc = ClusterConfig("qa","0.8.2-beta","localhost:2181", jmxEnabled = false)
    val serialize: String = ClusterConfig.serialize(cc)
    val noverison = serialize.replace(""","kafkaVersion":"0.8.2.0"""",""","kafkaVersion":"0.8.2-beta"""")
    val deserialize = ClusterConfig.deserialize(noverison)
    assert(deserialize.isSuccess === true)
    assert(cc == deserialize.get)
  }
}