text:
var B = require("hope-base");
var P = require("hope-hub-center-shared").protocol;
var log = B.log.for_category("center");
var _ = require("lodash");
var FE = require("./frontend");
var HeartBeatServer = require("./heartbeat_server");
var BuiltinHub = require("./built_in_hub");

var Center =
module.exports = function(config) {
  config = config || {};
  this.type = "Center";
  this.id = config.id || B.unique_id("HOPE_CENTER_");
  this.name = config.name || this.id;
  this.description = config.description || this.name;
  this.mnode = B.check(config.mnode, "center", "Should have a mnode to create");
  this.em = B.check(config.entity_manager,
    "center", "Should have a entity_manager to create");
  this.config = config;
  this.config_path = config.config_path;
  B.check(config.appbundle_path, "center", "should have an app bundle");
  this.appbundle_path = B.path.abs(config.appbundle_path, this.config_path);
  this.user_setting = this.load_user_setting();
  this.frontends = {};

  this.errors = [];

  var self = this;
  B.set_exception_hook(function(e, category, msg, type) {
    var stack = B.get_raw_stack(e);
    var err = {
      time: new Date(),
      subsystem: self.name,
      category: category,
      type: type || B.err.CHECK_FAIL,
      message: msg,
      stack: stack.slice(1)
    };
    e.$type = err.type;
    self.announce_error(err);
  });

  B.net.set_exception_hook(function(err) {
    if (_.isError(err)) {
      if (!err.$check) {
        var stack = B.get_raw_stack(err);
        err.$type = B.err.UNHANDLED_EXCEPTION;
        self.announce_error({
          time: new Date(),
          subsystem: self.name,
          category: "Unhandled Exception",
          type: B.err.UNHANDLED_EXCEPTION,
          message: err.message,
          stack: stack
        });
      }
      return err.$type;
    }

    return to_string(err);
  });

  if (config.dev_web_app) {
    this.frontends.dev = new FE.DevFrontEnd(this, config.dev_web_app);

    //TODO: Export to session-manager
    global.$hope__dev_webapp = this.frontends.dev.web_app;
  }
  if (config.user_web_app) {
    this.frontends.user = new FE.UserFrontEnd(this, config.user_web_app);
  }

  if (this.frontends.dev) {
    this.frontends.dev.$forward = this.frontends.user;
  }

  if (config.heartbeat_server) {
    this.heartbeat_server = new HeartBeatServer(this, config.heartbeat_server);
  }

  this.built_in_hub = null;
  this.workflow_engine = config.workflow_engine;
  var self = this;
  this.workflow_engine.event.on("debug", function(data) {
    if (self.frontends.dev) {
      self.frontends.dev.graph_emit(data.workflow_id, "debug", data);
    }
  });
  this.workflow_engine.event.on("workflow_load", function(data) {
    _.forOwn(self.frontends, function(f) {
      f.setup_graph_socket(data.id);
    });
  });
};

Center.create$ = function(config) {
  var center = new Center(config);
  return center.init$().then(function() {
   return center;
 });
};

Center.prototype.get_info = function() {
  return {
    id: this.id,
    mnode_id: this.mnode.id
  };
};

Center.prototype.get_brief = function() {
  return {
    id: this.id,
    mnode_id: this.mnode.id
  };
};

Center.prototype.init$ = function() {
  var tasks = [];
  var self = this;
  tasks.push(this._init_em$());
  tasks.push(this.mnode.accept$(P.EM_FULLINFO, this.on_entities_fullinfo.bind(this)));
  tasks.push(this.mnode.accept$(P.CLAIM_AS_HUB, this.on_hub_claimed.bind(this)));
  tasks.push(this.mnode.subscribe_all$(P.ANNOUNCE_ERROR, this.announce_error.bind(this)));
  tasks.push(this.mnode.subscribe_all$(P.CLAIM_AS_HUB, this.on_hub_claimed.bind(this)));
  tasks.push(this.mnode.subscribe_all$(P.HUB_LEAVE, this.on_hub_left.bind(this)));
  tasks.push(this._init_frontends$());

  return Promise.all(tasks).then(function() {
    if (self.heartbeat_server) {
      self.heartbeat_server.enable();
    }
    return self.mnode.publish$(P.CLAIM_AS_CENTER, self.get_info());
  }).then(function() {
    return BuiltinHub.create$(self).then(function(hub) {
      self.built_in_hub = hub;
      return BuiltinHub.init$(hub, self);
    });
  }).then(function() {
    return self.mnode.enable_rpc$();
  }).then(function() {
    return self.em.app_store.list$().then(function(ids) {
      _.forEach(ids, function(id) {
        _.forOwn(self.frontends, function(f) {
          f.setup_app_socket(id);
        });
      });
    });
  }).then(function() {
    return self.em.graph_store.list$().then(function(ids) {
      _.forEach(ids, function(id) {
        _.forOwn(self.frontends, function(f) {
          f.setup_graph_socket(id);
        });
      });
    });
  });
};

Center.prototype.leave$ = function() {
  var self = this;

  return this.built_in_hub.leave$()
  .then(function() {
    self.mnode.disable_rpc$();
  })
  .then(function() {
    if (self.heartbeat_server) {
      self.heartbeat_server.disable();
    }
    var tasks = [];
    tasks.push(self.mnode.publish$(P.CENTER_LEAVE, self.get_brief()));
    tasks.push(self.mnode.clean_subscribe_all$());
    tasks.push(self.mnode.clean_subscribe$());
    tasks.push(self.mnode.clean_accepts$());
    return Promise.all(tasks);
  }).then(function() {
    return self.destroy_related_webapp$();
  }).finally(function() {
    return self.mnode.dispose$();
  });
};

Center.prototype.destroy_related_webapp = function() {
  var all = [];
  if (this.config.user_web_app) {
    all.push(this.config.user_web_app.$destroy());
  }
  if (this.config.dev_web_app) {
    all.push(this.config.dev_web_app.$destroy());
  }
  return Promise.all(all);
};

Center.prototype.on_hub_claimed = function(hub_info) {
  log("Hub Claimed", hub_info);
  var self = this;
  var hub_id = hub_info.id;
  var hub_mnode_id = hub_info.mnode_id;
  self.beat$(hub_id).done();//beat
  this.make_lock(hub_id).lock_as_promise$(function() {
    return self.em.hub__get$(hub_id)
    .then(function(hub) {
      if (_.isUndefined(hub)) {
        log("Found New Hub", hub_info);
        var tasks = [];
        tasks.push(self.mnode.subscribe$(hub_mnode_id, P.EM_CHANGED, self.on_entities_changed.bind(self)));
        tasks.push(self.mnode.send$(hub_mnode_id, P.NEED_EM_FULLINFO, self.get_info()));

        return Promise.all(tasks);
      }
    });
  }).done();
};

Center.prototype.force_hub_leave = function(hub_id) {
  var self = this;
  this.make_lock(hub_id).lock_as_promise$(function() {
    return self.em.hub__get$(hub_id).then(function(hub) {
      if (hub) {
        self.on_hub_left({
          id: hub_id,
          mnode_id: hub.mnode
        });
      }
    });
  }).done();
};

Center.prototype.on_hub_left = function(hub_brief) {
  log("Hub Left", hub_brief);
  var self = this;
  this.make_lock(hub_brief.id).lock_as_promise$(function() {
    return self.em.hub__remove$(hub_brief.id)
    .then(function() {
      if (self.heartbeat_server) {
        return self.heartbeat_server.leave$(hub_brief.id);
      }
    })
    .then(function() {
      var tasks = [];
      tasks.push(self.mnode.clean_subscribe$(hub_brief.mnode_id));
      return Promise.all(tasks);
    });
  }).done();
};

Center.prototype.on_entities_changed = function(data) {
  var hub_id = data.hub;
  var hub_mnode_id = data.hub_mnode_id;
  var list = data.list;
  var time = data.time;
  var self = this;
  self.beat$(hub_id).done();//beat
  log("EM_CHANGED From Hub", hub_id, data);
  this.make_lock(hub_id).lock_as_promise$(function() {
    return self.em.hub__get$(hub_id)
    .then(function(hub) {
      if (_.isUndefined(hub)) {
        log("EM_CHANGED hub not exist", hub_id);
        return self.mnode.send$(hub_mnode_id, P.NEED_EM_FULLINFO, self.get_info());
      }
      else if (check_emchanged_time_match(time, hub.timestamp)) {
        log("EM_CHANGED match", hub_id, time, "existing timestamp:", hub.timestamp);
        return self.em.update$(list)
        .then(function() {
          return self.em.hub__get$(hub_id);
        })
        .then(function(new_hub) {
          return self._set_hub_timestamp$(new_hub, time);
        });
      }
      else if (check_emchanged_time_new(time, hub.timestamp)) {
        log("EM_CHANGED ahead", hub_id, time, "existing timestamp:", hub.timestamp);
        return self.mnode.send$(hub_mnode_id, P.NEED_EM_FULLINFO, self.get_info());
      }
      else {
        log("EM_CHANGED old", hub_id, time, "existing timestamp:", hub.timestamp);
        return;
      }
    });
  }).done();
};

Center.prototype.on_entities_fullinfo = function(data) {
  var hub_id = data.hub;
  var list = data.list;
  var time = data.time;
  var self = this;
  self.beat$(hub_id).done();//beat
  log("EM_FULLINFO From Hub", hub_id);
  this.make_lock(hub_id).lock_as_promise$(function() {
    return self.em.hub__get$(hub_id)
    .then(function(hub) {
      if (_.isUndefined(hub)) {
        log("FULLINFO of New Hub", hub_id, time);
        return self.em.update$(list)
        .then(function() {
          return self.em.hub__get$(hub_id);
        })
        .then(function(new_hub) {
          return self._set_hub_timestamp$(new_hub, time);
        });
      }
      else if (check_fullinfo_time(time, hub.timestamp)) {
        log("FULLINFO of Existing Hub", hub_id, time, "existing timestamp:", hub.timestamp);
        return self.em.hub__remove$(hub_id)
        .then(function() {
          return self.em.update$(list);
        })
        .then(function() {
          return self._set_hub_timestamp$(hub, time);
        });
      }
      else {
        log("Old FULLINFO", hub_id, time, "existing timestamp:", hub.timestamp);
        return;
      }
    });
  }).done();
};

Center.prototype._ensure_user_exists$ = function(user, role, passwd) {
  var self = this;
  return self.em.user__find$(user, null).then(function(u) {
    if (u) {
      return false;
    }
    self.em.user__add$({
      id: user,
      name: user,
      role: role,
      passwd: passwd,
      appbundle_path: B.path.join(self.appbundle_path, user)
    });
    return true;
  });
};

Center.prototype._init_em$ = function() {
  var self = this;
  if (this.config.auth) {
    // default password is ""
    return self._ensure_user_exists$("admin", "admin", "LcCbizWvnANvw/Kc28Bfuw==").then(function(added) {
      if (!added) {
        // guest can be deleted
        return Promise.resolve();
      }
      return self._ensure_user_exists$("guest", "guest", "7lf26KynsWJIvOEM9QWHVQ==");
    });
  }
  return self.em.app__load_from_bundle$(self.appbundle_path, null);
};

Center.prototype._set_hub_timestamp$ = function(hub, timestamp) {
  hub.timestamp = timestamp;
  return this.em.hub_store.set$(hub.id, hub);
};

Center.prototype._init_frontends$ = function() {
  var tasks = [];

  if (this.frontends.dev) {
    tasks.push(this.frontends.dev.init$());
  }
  if (this.frontends.user) {
    tasks.push(this.frontends.user.init$());
  }
  return Promise.all(tasks);
};

Center.prototype.make_lock = function(key) {
  return B.lock.make("__HOPE__/CENTER/" + this.id + "/" +
    (_.isUndefined(key) ? "" : key));
};

Center.prototype.beat$ = function(hub_id) {
  var self = this;
  return Promise.resolve()
  .then(function() {
    if (self.heartbeat_server) {
      return self.heartbeat_server.beat$(hub_id);
    }
  });
};
// -----------------------------------------------
// Workflow related. all lock the graph_id.
//              each operation is atomic
// -----------------------------------------------
Center.prototype.workflow_create$ = function(graph) {
  _.forOwn(this.frontends, function(f) {
    f.setup_graph_socket(graph.id);
  });
  return this.em.graph__add$(graph);
};

Center.prototype.workflow_create_nr$ = function(graph) {
  _.forOwn(this.frontends, function(f) {
    f.setup_graph_socket(graph.id);
  });
  return this.em.graph__add_nodered$(graph, this.built_in_hub.id);
};

Center.prototype.workflow_update$ = function(graph) {
  _.forOwn(this.frontends, function(f) {
    f.setup_graph_socket(graph.id);
  });
  return this.em.graph__update$(graph);
};

Center.prototype.workflow_start$ = function(graph_id, tracing) {
  log("workflow_start", graph_id);
  var self = this;
  var graph;
  return this.make_lock(graph_id).lock_as_promise$(function() {
    return self.em.graph__get$(graph_id)
    .then(function(graph_json) {
      var specid_array = [];
      graph_json.graph.nodes.forEach(function(node) {
        specid_array.push(node.spec);
      });
      graph = graph_json;
      return self.em.spec__get$(specid_array);
    })
    .then(function(specs) {
      graph = self.em.graph__remove_unused_nr_config_node(graph, specs);
      // The specs we got from database is an array
      // However, the engine expects a hashtable for the specs
      // so need index it first
      return self.workflow_engine.start$(graph,
        _.keyBy(specs, "id"), tracing);
    });
  });
};

Center.prototype.workflow_remove$ = function(id) {
  if (this.workflow_engine.workflows[id] &&
    this.workflow_engine.workflows[id].status === "enabled") {
    return Promise.reject(new Error("workflow " + id + " is still running and cannot remove!"));
  }
  delete this.workflow_engine.workflows[id];
  _.forOwn(this.frontends, function(f) {
    f.remove_graph_socket(id);
  });
  return this.em.graph__remove$(id);
};

Center.prototype.workflow_get_status = function(graph_id) {
  // need to interpret internal status to external
  switch (this.workflow_engine.get_status(graph_id)) {
    case "unloaded":
      return "Non-exist";
    case "enabled":
      return "Working";
    case "disabled":
      return "Paused";
    case "installed":
      return "Stopped";
    case "loaded":
      return "Idle";
  }
};

Center.prototype.workflow_get_trace = function(graph_id) {
  log("workflow_get_trace", graph_id);
  return this.workflow_engine.get_trace(graph_id).trace;
};

Center.prototype.workflow_get_debug_trace = function(graph_id) {
  log("workflow_get_debug_trace", graph_id);
  return this.workflow_engine.get_debug_trace(graph_id).trace;
};

Center.prototype.workflow_set_debug_for_node$ = function(graph_id, node_id, is_debug) {
  log("workflow_set_debug_for_node", graph_id);
  var self = this;
  // We need to persistent this change as well
  return this.make_lock(graph_id).lock_as_promise$(function() {
    self.workflow_engine.set_debug_for_node(graph_id, node_id, is_debug);
    return self.workflow_update$(
      self.workflow_engine.ensure_get_workflow(graph_id).json);
  });
};

Center.prototype.workflow_stop$ = function(graph_id) {
  log("workflow_stop", graph_id);
  var self = this;
  return this.make_lock(graph_id).lock_as_promise$(function() {
    return self.workflow_engine.stop$(graph_id);
  });
};

Center.prototype.workflow_pause$ = function(graph_id) {
  log("workflow_pause", graph_id);
  var self = this;
  return this.make_lock(graph_id).lock_as_promise$(function() {
    return self.workflow_engine.pause$(graph_id);
  });
};

Center.prototype.workflow_resume$ = function(graph_id) {
  log("workflow_resume", graph_id);
  var self = this;
  return this.make_lock(graph_id).lock_as_promise$(function() {
    return self.workflow_engine.resume$(graph_id);
  });
};

// -------------------------------------------------
// Helper
// -------------------------------------------------
function check_fullinfo_time(coming_time, existing_time) {
  return B.time.compare_hrtime(coming_time.now, existing_time.now) === 1;
}

function check_emchanged_time_match(coming_time, existing_time) {
  return B.time.compare_hrtime(coming_time.last, existing_time.now) === 0;
}

function check_emchanged_time_new(coming_time, existing_time) {
  return B.time.compare_hrtime(coming_time.now, existing_time.now) === 1;
}

Center.prototype.get_user_proxy = function(type, hub_id) {
  var self = this;
  type = type || "Center";
  if(type === "Center") {
    return self.user_setting.proxy;
  } else {
    B.check(hub_id, "center", "get hub user proxy must provide hub_id");
    self.em.hub__get$(hub_id).then(function(hub) {
      return self.mnode.invoke_rpc$(hub.mnode, "get_user_proxy");
    });
  }
};

Center.prototype.set_user_proxy = function(value) {
  var self = this;
  var apply_to_all_hub = value.apply_to_all_hub;
  delete value['apply_to_all_hub'];
  this.user_setting.proxy = value;
  this.store_user_setting();
  if(apply_to_all_hub) {
    this.em.hub__list$().then(function(hubs) {
      hubs = hubs || [];
      hubs.map(function(hub) {
        if(hub.type !== "builtin") {
          self.mnode.invoke_rpc$(hub.mnode, "set_user_proxy", value);
        }
      });
    }).then(function() {
      return;
    });
  }
};

Center.prototype.get_npm_account = function() {
  return this.user_setting.npm;
};

Center.prototype.set_npm_account = function(value) {
  this.user_setting.npm = value;
  this.store_user_setting();
};
Center.prototype.load_user_setting = function() {
  var json_path = B.path.abs("./user_setting.json", this.config.config_path);
  var user_setting = {};
  if(B.fs.file_exists(json_path)) {
    var json_content = B.fs.read_json(json_path);
    user_setting = json_content?json_content:{};
  } else {
    user_setting = {npm:{},proxy:{}};
    B.fs.write_json(json_path, user_setting);
  }
  return user_setting;
};

Center.prototype.store_user_setting = function() {
  var json_path = B.path.abs("./user_setting.json", this.config.config_path);
  B.fs.write_json(json_path, this.user_setting);
};

// -------------------------------------------------
// rpc invoke
// -------------------------------------------------

Center.prototype.add_hope_thing$ = function(thing) {
  var self = this;
  return this.em.hub__get$(thing.hub)
  .then(function(hub) {
    return self.mnode.invoke_rpc$(hub.mnode, "add_hope_thing", thing);
  })
  .then(function(data) {
    self.on_entities_changed(data);
    return;
  });
};

Center.prototype.install_hope_thing$ = function(hub_id, name, version) {
  var self = this;
  var send_hub = hub_id;
  return this.em.hub__get$(hub_id)
    .then(function(hub) {
      send_hub = hub;
      return self.mnode.invoke_rpc$(hub.mnode, "install_hope_thing", [name, version, hub_id]);
    })
    .then(function(data) {
      self.on_entities_changed(data);
      return;
    });
};

Center.prototype.update_hope_thing$ = function(thing) {
  var self = this;
  return this.em.thing__get_hub$(thing.id)
  .then(function(hub) {
    return self.mnode.invoke_rpc$(hub.mnode, "update_hope_thing", thing);
  })
  .then(function(data) {
    self.on_entities_changed(data);
    return;
  });
};

Center.prototype.remove_hope_thing$ = function(thing_id) {
  var self = this;
  return this.em.thing__get_hub$(thing_id)
  .then(function(hub) {
    return self.mnode.invoke_rpc$(hub.mnode, "remove_hope_thing", thing_id);
  })
  .then(function(data) {
    self.on_entities_changed(data);
    return;
  });
};

Center.prototype.add_hope_service$ = function(service) {
  var self = this;
  return this.em.thing__get_hub$(service.thing)
  .then(function(hub) {
    return self.mnode.invoke_rpc$(hub.mnode, "add_hope_service", service);
  })
  .then(function(data) {
    self.on_entities_changed(data);
    return;
  });
};

Center.prototype.install_hope_service$ = function(thing, name, version) {
  var self = this;
  return this.em.thing__get_hub$(thing)
    .then(function(hub) {
      return self.mnode.invoke_rpc$(hub.mnode, "install_hope_service", [name, version, thing]);
    })
    .then(function(data) {
      self.on_entities_changed(data);
      return;
    });
};

Center.prototype.update_hope_service$ = function(service) {
  var self = this;
  return this.em.service__get_hub$(service.id)
  .then(function(hub) {
    return self.mnode.invoke_rpc$(hub.mnode, "update_hope_service", service);
  })
  .then(function(data) {
    self.on_entities_changed(data);
    return;
  });
};

Center.prototype.remove_hope_service$ = function(service_id) {
  var self = this;
  return this.em.service__get_hub$(service_id)
  .then(function(hub) {
    return self.mnode.invoke_rpc$(hub.mnode, "remove_hope_service", service_id);
  })
  .then(function(data) {
    self.on_entities_changed(data);
    return;
  });
};

Center.prototype.list_service_files$ = function(service_id) {
  var self = this;
  return this.em.service__get_hub$(service_id)
  .then(function(hub) {
    return self.mnode.invoke_rpc$(hub.mnode, "list_service_files", service_id);
  });
};

Center.prototype.read_service_file$ = function(service_id, file_path) {
  var self = this;
  return this.em.service__get_hub$(service_id)
  .then(function(hub) {
    return self.mnode.invoke_rpc$(hub.mnode, "read_service_file", [service_id, file_path]);
  });
};

Center.prototype.write_service_file$ = function(service_id, file_path, content) {
  var self = this;
  var hub;
  B.check(!self.workflow_engine.has_started_workflows(), "center",
    "there still has started workflows, cannnot write_service_file");
  return this.em.service__get_hub$(service_id)
  .then(function(_hub) {
    hub = _hub;
    return self.mnode.invoke_rpc$(hub.mnode, "write_service_file", [service_id, file_path, content]);
  })
  .then(function() {
    return self.mnode.invoke_rpc$(hub.mnode, "reload_service", service_id);
  });
};

Center.prototype.remove_service_file$ = function(service_id, file_path) {
  var self = this;
  var hub;
  B.check(!self.workflow_engine.has_started_workflows(), "center",
    "there still has started workflows, cannnot remove_service_file");
  return this.em.service__get_hub$(service_id)
  .then(function(_hub) {
    hub = _hub;
    return self.mnode.invoke_rpc$(hub.mnode, "remove_service_file", [service_id, file_path]);
  })
  .then(function() {
    return self.mnode.invoke_rpc$(hub.mnode, "reload_service", service_id);
  });

};

Center.prototype.publish_hope_service$ = function(service_id, package_json) {
  var settings = {};
  var self = this;

  if (self.user_setting) {
    var proxy = self.user_setting.proxy;
    if (proxy && proxy.http_proxy) {
      settings.http = proxy.http_proxy;
    }
    if (proxy && proxy.https_proxy) {
      settings.https = proxy.https_proxy;
    }

    var npm = self.user_setting.npm;
    if (npm && npm.token) {
      settings.auth = {token: npm.token};
    }
    else if (npm && npm.username) {
      settings.auth = {username: npm.username, password: npm.password, email: npm.email};
    }
  }
  return this.em.service__get_hub$(service_id)
  .then(function(hub) {
    return self.mnode.invoke_rpc$(hub.mnode, "publish_hope_service", [service_id, package_json, settings]);
  });
};

Center.prototype.install_service_package$ = function(service_id, package_name, version) {
  var self = this;
  return this.em.service__get_hub$(service_id)
  .then(function(hub) {
    return self.mnode.invoke_rpc$(hub.mnode, "install_service_package", [service_id, package_name, version]);
  });
};

Center.prototype.uninstall_service_package$ = function(service_id, package_name) {
  var self = this;
  return this.em.service__get_hub$(service_id)
  .then(function(hub) {
    return self.mnode.invoke_rpc$(hub.mnode, "uninstall_service_package", [service_id, package_name]);
  });
};

var exc_seq = 1;

Center.prototype.announce_error = function(e) {
  e.seq = exc_seq++;
  if (this.frontends.dev) {
    this.frontends.dev.sys_emit("error", e);
  }
  if (this.errors.length > 200) {
    this.errors = this.errors.slice(-100);
  }
  this.errors.push(e);
  console.log(e);
};


text:
layout: page
title: Mix
category: basics
order: 9
lang: bg
---

Before we can dive into the deeper waters of Elixir we first need to learn about mix. If you're familiar with Ruby mix is Bundler, RubyGems, and Rake combined. It's a crucial part of any Elixir project and in this lesson we're going to explore just a few of it's great features. To see all that mix has to offer run `mix help`.

Until now we've been working exclusively within `iex` which has limitations.  In order to build something substantial we need to divide our code up into many files to effectively manage it, mix let's us do that with projects.

{% include toc.html %}

## New Projects

When we're ready to create a new Elixir project, mix makes it easy with the `mix new` command.  This will generate our project's folder structure and necessary boilerplate.  This is pretty straight forward, so let's get started:

```bash
$ mix new example
```

From the output we can see that mix has created our directory and a number of boilerplate files:

```bash
* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/example.ex
* creating test
* creating test/test_helper.exs
* creating test/example_test.exs
```

In this lesson we're going to focus our attention on `mix.exs`.  Here we configure our application, dependencies, environment, and version.  Open the file in your favorite editor, you should see something like this (comments removed for brevity):

```elixir
defmodule Example.Mixfile do
  use Mix.Project

  def project do
    [app: :example,
     version: "0.0.1",
     elixir: "~> 1.0",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     deps: deps]
  end

  def application do
    [applications: [:logger]]
  end

  defp deps do
    []
  end
end
```

The first section we'll look at is `project`.  Here we define the name of our application (`app`), specify our version (`version`), Elixir version (`elixir`), and finally our dependencies (`deps`).

The `application` section is used during the generation of our application file which we'll cover next.

## Interactive

It may be necessary to use `iex` within the context of our application.  Thankfully for us, mix makes this easy.  We can start a new `iex` session:

```bash
$ iex -S mix
```

Starting `iex` this way will load your application and dependencies into the current runtime.

## Compilation

Mix is smart and will compile your changes when necessary, but it may still be necessary explicitly compile your project.  In this section we'll cover how to compile our project and what compilation does.

To compile a mix project we only need to run `mix compile` in our base directory:

```bash
$ mix compile
```

There isn't much to our project so the output isn't too exciting but it should complete successfully:

```bash
Compiled lib/example.ex
Generated example app
```

When we compile a project mix creates a `_build` directory for our artifacts.  If we look inside `_build` we will see our compiled application: `example.app`.

## Manage Dependencies

Our project doesn't have any dependencies but will shortly, so we'll go ahead and cover defining dependencies and fetching them.

To add a new dependency we need to first add it to our `mix.exs` in the `deps` section.  Our dependency list is comprised of tuples with two required values and one optional: The package name as an atom, the version string, and optional options.

For this example let's look at a project with dependencies, like [phoenix_slim](https://github.com/doomspork/phoenix_slim):

```elixir
def deps do
  [{:phoenix, "~> 1.1 or ~> 1.2"},
   {:phoenix_html, "~> 2.3"},
   {:cowboy, "~> 1.0", only: [:dev, :test]},
   {:slime, "~> 0.14"}]
end
```

As you probably discerned from the dependencies above, the `cowboy` dependency is only necessary during development and test.

Once we've defined our dependencies there is one final step, fetching them.  This is analogous to `bundle install`:

```bash
$ mix deps.get
```

That's it!  We've defined and fetched our project dependencies.  Now we're prepared to add dependencies when the time comes.

## Environments

Mix, much like Bundler, supports differing environments.  Out of the box mix works with three environments:

+ `:dev` — The default environment.
+ `:test` — Used by `mix test`. Covered further in our next lesson.
+ `:prod` — Used when we ship our application to production.

The current environment can be accessed using `Mix.env`.  As expected, the environment can be changed via the `MIX_ENV` environment variable:

```bash
$ MIX_ENV=prod mix compile
```

redpajama_set_name: RedPajamaGithub


text:
package com.pushtechnology.adapters.rest.publication;

/**
 * Update context for an endpoint.
 *
 * @param <T> The type of updates the context accepts
 * @author Push Technology Limited
 */
public interface UpdateContext<T> {
    /**
     * Publish an update to a Diffusion server.
     */
    void publish(T value);
}


text:
{% extends "layout.html" %}
{% load template_tags %}
{% block title %}
  EA Summary
{% endblock %}
{% block content %}

Survey Completion by household in {{location.type.name}} {{ location.name }}

    {% if selected_ea %}

Enumeration Area: {{ selected_ea.name }}

    {% endif %}
    {% if interviewer %}

Interviewer: {{ interviewer.name }} (Mobile Numbers: {{ interviewer.ussd_access | display_list}} )

    {% endif %}
    {% if completion_rates %}

Percent Completion: {{ completion_rates.percent_completed_households }}%

    {% endif %}

          HH Code
          Household Head
          Total number of members in Household
          Total number of members Completed
          Date Completed
          Actions

        {% for interviewed in completion_rates.interviewed_households %}

                {{ interviewed.household.house_number }}
                {{ interviewed.household.get_head.surname.capitalize }}
                {{ interviewed.household.members.count }}
                {{ interviewed.number_of_member_interviewed }}
                {{ interviewed.date_interviewed|default_if_none:'--' }}
                view

        {% endfor %}

{% endblock %}
{% block javascripts %}
  <link rel="stylesheet" href="{{ STATIC_URL }}css/dataTables.bootstrap.css" type="text/css">

{% include 'max_display_per_page_form.html' %}
{% endblock %}


text:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#dddddd"
    android:paddingLeft="3dp"
    android:paddingRight="3dp"
    android:clickable="true">

    <ListView android:id="@id/android:list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="#cecece"
        android:dividerHeight="0.3dp"
        android:choiceMode="singleChoice"
        android:background="@android:color/background_light"
        android:textColor="@android:color/black"/>

    <TextView android:id="@id/android:empty"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#FFFFFF"
        android:text="Loading..."
        android:textColor="@android:color/black"
        android:gravity="center_vertical|center_horizontal" />
</LinearLayout>


text:
/*!
 * Seed specific dependancies
 */

var Edge = require('./edge/model')
  , errors = require('../errors/graph')
  , DBRef = require('../schematypes/dbref');

/**
 * # refreshLookups
 *
 * Ensure that the hash of model has all the
 * correct ID lookups.
 *
 * @param {Seed.Hash} hash to refresh
 * @api private
 */

exports.refreshLookups = function (hash) {
  var arr = hash.toArray();
  hash.flush(true);
  for (var i = 0; i < arr.length; i++) {
    var key = '/' + arr[i].value.type + '/' + arr[i].value.id
      , value = arr[i].value;
    hash.set(key, value, true);
  }
};

/**
 * # buildEdge
 *
 * Given two models and relation tag, construct
 * a new Edge model and return it. Must be called
 * with a graph's context.
 *
 * @context {Seed.Graph}
 * @param {Seed.Model|DBRef} vertice x
 * @param {Seed.Model|DBRef} vertice y
 * @param {String} relation tag
 * @param {Object} attributes to attach to edge
 * @returns {Seed.Model} instance of Graph#Edge
 * @api private
 */

exports.buildEdge = function (vertX, vertY, rel, attrs) {
  var type = this.type + '_edge'
    , edge = new Edge({
          x: vertX
        , y: vertY
        , rel: rel
        , attributes: attrs
      }, { parent: this, type: type });
  return edge;
};

/**
 * # getEdge
 *
 * Given two vertices and a relation tag,
 * determine if there is an edge model constructed
 * in a constructed graph's hash of edges. Must be
 * called with the graph's context.
 *
 * @context {Seed.Graph}
 * @param {Seed.Model|DBRef} vertice x
 * @param {Seed.Model|DBRef} vertice y
 * @param {String} relation tag
 * @returns {Seed.Model} instance of Graph#Edge (or undefined)
 * @api private
 */

exports.getEdge = function (vertX, vertY, rel) {
  var x =
    { id: vertX.id || vertX.$id
    , type: vertX.type || vertX.$rel };

  var y =
    { id: vertY.id || vertY.$id
    , type: vertY.type || vertY.$rel };

  return this._edges.find({
    $and:
      [ { $or:
        [ { 'x.id': x.id, 'x.type': x.type }
        , { 'x.$id': x.id, 'x.$rel': x.type } ] }
      , { $or:
        [ { 'y.id': y.id, 'y.type': y.type }
        , { 'y.$id': y.id, 'y.$rel': y.type } ] }
      , { 'rel': rel } ]
  }).at(0);
};

/**
 * # fetchEdges
 *
 * Given a vertices (either x or y), connect to the graph's
 * store and fetch all edges related to that model. The vertice
 * can either be a constructed model or a DBRef object. The fetch
 * can further be filtered by the relation tag. All fetched edges
 * will be constructed into an Edge model and placed in the graph's
 * hash of edges. Must be called with the graph's context.
 *
 * @context {Seed.Graph}
 * @param {Seed.Model|DBRef} vertice (can be x or y)
 * @param {String} relation tag (optional)
 * @param {Function} callback to execute on completion
 * @cbparam {Object} error if issue with fetch or parse
 * @api private
 */

exports.fetchEdges = function (vert, rel, cb) {
  if ('function' === typeof rel) {
    cb = rel;
    rel = null
  }

  // query builder
  var query = { $and:
    [ { $or:
      [ { 'x.$id': vert.id
        , 'x.$ref': vert.type }
      , { 'y.$id': vert.id
        , 'y.$ref': vert.type }
      ] }
    ]
  };

  if (rel && 'string' === typeof rel)
    query.$and.push({ 'rel': rel });

  pullEdges.call(this, query, cb);
};

/**
 * # fetchOutEdges
 *
 * Same as `fetchEdges` execept expects vertice supplied
 * to be the `x` vertice in the edge.
 *
 * @context {Seed.Graph}
 * @param {Seed.Model|DBRef} x vertice
 * @param {String} relation tag (optional)
 * @param {Function} callback to execute on completion
 * @cbparam {Object} error if issue with fetch or parse
 * @api private
 */

exports.fetchOutEdges = function (vert, rel, cb) {
  // check for rel param
  if ('function' === typeof rel) {
    cb = rel;
    rel = null
  }

  // query builder
  var query = {
      'x.$id': vert.id
    , 'x.$ref': vert.type
  };

  if (rel && 'string' === typeof rel)
    query.rel = rel;

  pullEdges.call(this, query, cb);
};

/**
 * # fetchInEdges
 *
 * Same as `fetchEdges` execept expects vertice supplied
 * to be the `y` vertice in the edge.
 *
 * @context {Seed.Graph}
 * @param {Seed.Model|DBRef} y vertice
 * @param {String} relation tag (optional)
 * @param {Function} callback to execute on completion
 * @cbparam {Object} error if issue with fetch or parse
 * @api private
 */

exports.fetchInEdges = function (vert, rel, cb) {
  // check for rel param
  if ('function' === typeof rel) {
    cb = rel;
    rel = null
  }

  // query builder
  var query = {
      'y.$id': vert.id
    , 'y.$ref': vert.type
  };

  if (rel && 'string' === typeof rel)
    query.rel = rel;

  pullEdges.call(this, query, cb);
};

/*!
 * # pullEdges
 *
 * Powers `fetchEdges` and equivalant helper methods.
 * Performs a query on the storage engine.
 *
 * @context {Seed.Graph}
 * @param {Object} query
 * @param {Function} callback
 * @api double-secret
 */

function pullEdges (query, cb) {
  // base checks and reassociation
  if (!this.store) return cb(errors.create('no store'));

  // empty callback
  if ('function' !== typeof cb)
    cb = function () {};

  // variables
  var self = this
    , type = this.type + '_edge';

  // given array fetched, load edges into graph
  function parseEdges (data) {
    for (var i = 0; i < data.length; i++) {
      var rawEdge = data[i]
        , rawX = new DBRef(null, rawEdge.x).getValue()
        , rawY = new DBRef(null, rawEdge.y).getValue()
        , vertX = (self.has(rawX.$ref, rawX.$id))
          ? self.get(rawX.$ref, rawX.$id)
          : rawX
        , vertY = (self.has(rawY.$ref, rawY.$id))
          ? self.get(rawY.$ref, rawY.$id)
          : rawY
        , edge = exports.getEdge.call(self, vertX, vertY, rawEdge.rel);

      if (!edge) {
        edge = exports.buildEdge.call(self, vertX, vertY, rawEdge.rel, rawEdge.attributes);
        edge.set('_id', rawEdge._id, { silent: true });
        edge.flag('new', false, true);
        edge.flag('dirty', false, true);
        self._edges.set(edge.id, edge);
      }
    }

    exports.refreshLookups.call(self, self._edges);
    cb(null);
  }

  // begin the query
  this.store
    .sync('fetch', { type: type }, query)
    .then(parseEdges, function rejected (err) { cb(err) });
}


text:
layout: post
title: "Detecting when the active Space changes"
tags:
  - Cocoa
  - Programming
date: 11 November 2007 00:00:00
---

OK, so there's been a discussion about this on the cocoa-dev list of late, and no-one answered the question - I figure I'll jump into the fray given that this is exactly what I've been working on with Hyperspaces.

There are two things you have to understand up front:

**There is a notification "com.apple.switchSpaces" posted when a user chooses to switch spaces via the menu extra**. This notification can also be (ab)used to switch spaces using your app as well - however…

**There is no other notification that your active space has changed**, and it is only posted by the menu extra. **You need to check for changes from the CoreGraphicsServer** - the easiest way to do that is as follows. It's up to you to write the code that uses this, but attaching it to a simple NSTimer would probably work just fine.

{% highlight obj-c %}
-(NSNumber *)CGSSpaceNumber
{
  int spaceNumber = -1;
  CGSGetWorkspace(_CGSDefaultConnection(), &spaceNumber);
  return [NSNumber numberWithInt: (spaceNumber - 1)];
}
{% endhighlight %}

I use this method in [Hyperspaces][hsurl], and it works just fine for my purposes (with the requisite delay associated with my application having to scan for changes). Apple's Eric Schlegel [explains the reasoning behind why there is no notification on the cocoa-dev list][cocoa-dev post]. Long story short, it sounds like Apple's not quite done developing Spaces yet, and they don't want people relying on APIs that aren't finalised.

 [hsurl]: http://thecocoabots.com/hyperspaces/
 [cocoa-dev post]: http://www.cocoabuilder.com/archive/message/cocoa/2007/11/11/192797


text:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="helloConstructorBean" class="com.spike.java.HelloWorld">
        <constructor-arg value="Spring from Constructor"/>
    </bean>

</beans>


text:
package org.zstack.core.externalservice;

public interface RemoteExternalService extends ExternalService {
}


text:
FROM phusion/baseimage:latest
MAINTAINER bySabi <flxinformatico@gmail.com>

# Set correct environment variables.
ENV DEBIAN_FRONTEND noninteractive
ENV HOME /root
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8
RUN \
	echo "Europe/Madrid" > /etc/timezone && \
	dpkg-reconfigure -f noninteractive tzdata

RUN \
	apt-get update 1>/dev/null && apt-get upgrade -y -q --no-install-recommends && \
	apt-get install -y --no-install-recommends software-properties-common

# Install Mosquitto MQTT Broker Server
RUN \
	add-apt-repository -y ppa:mosquitto-dev/mosquitto-ppa && \
	apt-get update 1>/dev/null && \
	apt-get install -y --no-install-recommends mosquitto mosquitto-clients

COPY usr/mosquitto.sh /etc/service/mosquitto/run

#mosquitto_sub -h dns.iguanalab.lan -d -t hello/world
#mosquitto_pub -h dns.iguanalab.lan -d -t hello/world -m "La prueba"

# Use baseimage-docker's init system.
CMD ["/sbin/my_init"]


text:
namespace cc {

ScrollbarLayerImplBase::ScrollbarLayerImplBase(
    LayerTreeImpl* tree_impl,
    int id,
    ScrollbarOrientation orientation,
    bool is_left_side_vertical_scrollbar,
    bool is_overlay)
    : LayerImpl(tree_impl, id),
      is_overlay_scrollbar_(is_overlay),
      thumb_thickness_scale_factor_(1.f),
      current_pos_(0.f),
      clip_layer_length_(0.f),
      scroll_layer_length_(0.f),
      orientation_(orientation),
      is_left_side_vertical_scrollbar_(is_left_side_vertical_scrollbar),
      vertical_adjust_(0.f) {}

ScrollbarLayerImplBase::~ScrollbarLayerImplBase() {
  layer_tree_impl()->UnregisterScrollbar(this);
}

void ScrollbarLayerImplBase::PushPropertiesTo(LayerImpl* layer) {
  LayerImpl::PushPropertiesTo(layer);
  DCHECK(layer->IsScrollbarLayer());
  ScrollbarLayerImplBase* scrollbar_layer = ToScrollbarLayer(layer);
  scrollbar_layer->set_is_overlay_scrollbar(is_overlay_scrollbar_);
  scrollbar_layer->SetScrollElementId(scroll_element_id());
}

bool ScrollbarLayerImplBase::IsScrollbarLayer() const {
  return true;
}

void ScrollbarLayerImplBase::SetScrollElementId(ElementId scroll_element_id) {
  if (scroll_element_id_ == scroll_element_id)
    return;

  layer_tree_impl()->UnregisterScrollbar(this);
  scroll_element_id_ = scroll_element_id;
  layer_tree_impl()->RegisterScrollbar(this);
}

bool ScrollbarLayerImplBase::SetCurrentPos(float current_pos) {
  if (current_pos_ == current_pos)
    return false;
  current_pos_ = current_pos;
  NoteLayerPropertyChanged();
  return true;
}

float ScrollbarLayerImplBase::current_pos() const {
  DCHECK(!layer_tree_impl()->ScrollbarGeometriesNeedUpdate());
  return current_pos_;
}

float ScrollbarLayerImplBase::clip_layer_length() const {
  DCHECK(!layer_tree_impl()->ScrollbarGeometriesNeedUpdate());
  return clip_layer_length_;
}

float ScrollbarLayerImplBase::scroll_layer_length() const {
  DCHECK(!layer_tree_impl()->ScrollbarGeometriesNeedUpdate());
  return scroll_layer_length_;
}

float ScrollbarLayerImplBase::vertical_adjust() const {
  DCHECK(!layer_tree_impl()->ScrollbarGeometriesNeedUpdate());
  return vertical_adjust_;
}

bool ScrollbarLayerImplBase::CanScrollOrientation() const {
  PropertyTrees* property_trees = layer_tree_impl()->property_trees();
  const auto* scroll_node =
      property_trees->scroll_tree.FindNodeFromElementId(scroll_element_id_);
  DCHECK(scroll_node);
  // TODO(bokan): Looks like we sometimes get here without a ScrollNode. It
  // should be safe to just return false here (we don't use scroll_element_id_
  // anywhere else) so we can merge the fix. Once merged, will investigate the
  // underlying cause. https://crbug.com/924068.
  if (!scroll_node)
    return false;

  if (orientation() == ScrollbarOrientation::HORIZONTAL) {
    if (!scroll_node->user_scrollable_horizontal)
      return false;
  } else {
    if (!scroll_node->user_scrollable_vertical)
      return false;
  }

  // Ensure the clip_layer_length and scroll_layer_length values are up-to-date.
  // TODO(pdr): Instead of using the clip and scroll layer lengths which require
  // an update, refactor to use the scroll tree (ScrollTree::MaxScrollOffset
  // as in LayerTreeHostImpl::TryScroll).
  layer_tree_impl()->UpdateScrollbarGeometries();

  // Ensure clip_layer_length is smaller than scroll_layer_length, not including
  // small deltas due to floating point error.
  return !MathUtil::IsFloatNearlyTheSame(clip_layer_length(),
                                         scroll_layer_length()) &&
         clip_layer_length() < scroll_layer_length();
}

void ScrollbarLayerImplBase::SetVerticalAdjust(float vertical_adjust) {
  if (vertical_adjust_ == vertical_adjust)
    return;
  vertical_adjust_ = vertical_adjust;
  NoteLayerPropertyChanged();
}

void ScrollbarLayerImplBase::SetClipLayerLength(float clip_layer_length) {
  if (clip_layer_length_ == clip_layer_length)
    return;
  clip_layer_length_ = clip_layer_length;
  NoteLayerPropertyChanged();
}

void ScrollbarLayerImplBase::SetScrollLayerLength(float scroll_layer_length) {
  if (scroll_layer_length_ == scroll_layer_length)
    return;
  scroll_layer_length_ = scroll_layer_length;
  NoteLayerPropertyChanged();
  return;
}

void ScrollbarLayerImplBase::SetThumbThicknessScaleFactor(float factor) {
  if (thumb_thickness_scale_factor_ == factor)
    return;
  thumb_thickness_scale_factor_ = factor;
  NoteLayerPropertyChanged();
}

gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRectWithThumbThicknessScale(
    float thumb_thickness_scale_factor) const {
  // Thumb extent is the length of the thumb in the scrolling direction, thumb
  // thickness is in the perpendicular direction. Here's an example of a
  // horizontal scrollbar - inputs are above the scrollbar, computed values
  // below:
  //
  //    |<------------------- track_length_ ------------------->|
  //
  // |--| <-- start_offset
  //
  // +--+----------------------------+------------------+-------+--+
  // |<||                            |##################|       ||>|
  // +--+----------------------------+------------------+-------+--+
  //
  //                                 |<- thumb_length ->|
  //
  // |<------- thumb_offset -------->|
  //
  // For painted, scrollbars, the length is fixed. For solid color scrollbars we
  // have to compute it. The ratio of the thumb's length to the track's length
  // is the same as that of the visible viewport to the total viewport, unless
  // that would make the thumb's length less than its thickness.
  //
  // vertical_adjust_ is used when the layer geometry from the main thread is
  // not in sync with what the user sees. For instance on Android scrolling the
  // top bar controls out of view reveals more of the page content. We want the
  // root layer scrollbars to reflect what the user sees even if we haven't
  // received new layer geometry from the main thread.  If the user has scrolled
  // down by 50px and the initial viewport size was 950px the geometry would
  // look something like this:
  //
  // vertical_adjust_ = 50, scroll position 0, visible ratios 99%
  // Layer geometry:             Desired thumb positions:
  // +--------------------+-+   +----------------------+   <-- 0px
  // |                    |v|   |                     #|
  // |                    |e|   |                     #|
  // |                    |r|   |                     #|
  // |                    |t|   |                     #|
  // |                    |i|   |                     #|
  // |                    |c|   |                     #|
  // |                    |a|   |                     #|
  // |                    |l|   |                     #|
  // |                    | |   |                     #|
  // |                    |l|   |                     #|
  // |                    |a|   |                     #|
  // |                    |y|   |                     #|
  // |                    |e|   |                     #|
  // |                    |r|   |                     #|
  // +--------------------+-+   |                     #|
  // | horizontal  layer  | |   |                     #|
  // +--------------------+-+   |                     #|  <-- 950px
  // |                      |   |                     #|
  // |                      |   |##################### |
  // +----------------------+   +----------------------+  <-- 1000px
  //
  // The layer geometry is set up for a 950px tall viewport, but the user can
  // actually see down to 1000px. Thus we have to move the quad for the
  // horizontal scrollbar down by the vertical_adjust_ factor and lay the
  // vertical thumb out on a track lengthed by the vertical_adjust_ factor. This
  // means the quads may extend outside the layer's bounds.

  // With the length known, we can compute the thumb's position.
  float track_length = TrackLength();
  int thumb_length = ThumbLength();
  int thumb_thickness = ThumbThickness();
  float maximum = scroll_layer_length() - clip_layer_length();

  // With the length known, we can compute the thumb's position.
  float clamped_current_pos = base::ClampToRange(current_pos(), 0.0f, maximum);

  int thumb_offset = TrackStart();
  if (maximum > 0) {
    float ratio = clamped_current_pos / maximum;
    float max_offset = track_length - thumb_length;
    thumb_offset += static_cast<int>(ratio * max_offset);
  }

  float thumb_thickness_adjustment =
      thumb_thickness * (1.f - thumb_thickness_scale_factor);

  gfx::RectF thumb_rect;
  if (orientation_ == HORIZONTAL) {
    thumb_rect = gfx::RectF(thumb_offset,
                            vertical_adjust_ + thumb_thickness_adjustment,
                            thumb_length,
                            thumb_thickness - thumb_thickness_adjustment);
  } else {
    thumb_rect = gfx::RectF(
        is_left_side_vertical_scrollbar_
            ? bounds().width() - thumb_thickness
            : thumb_thickness_adjustment,
        thumb_offset,
        thumb_thickness - thumb_thickness_adjustment,
        thumb_length);
  }

  return gfx::ToEnclosingRect(thumb_rect);
}

gfx::Rect ScrollbarLayerImplBase::ComputeExpandedThumbQuadRect() const {
  DCHECK(is_overlay_scrollbar());
  return ComputeThumbQuadRectWithThumbThicknessScale(1.f);
}

gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const {
  return ComputeThumbQuadRectWithThumbThicknessScale(
      thumb_thickness_scale_factor_);
}

void ScrollbarLayerImplBase::SetOverlayScrollbarLayerOpacityAnimated(
    float opacity) {
  DCHECK(is_overlay_scrollbar());
  if (!layer_tree_impl())
    return;

  PropertyTrees* property_trees = layer_tree_impl()->property_trees();

  EffectNode* node = property_trees->effect_tree.Node(effect_tree_index());
  if (node->opacity == opacity)
    return;

  node->opacity = opacity;
  node->effect_changed = true;
  property_trees->changed = true;
  property_trees->effect_tree.set_needs_update(true);
  layer_tree_impl()->set_needs_update_draw_properties();
}

LayerTreeSettings::ScrollbarAnimator
ScrollbarLayerImplBase::GetScrollbarAnimator() const {
  return layer_tree_impl()->settings().scrollbar_animator;
}

bool ScrollbarLayerImplBase::HasFindInPageTickmarks() const {
  return false;
}

float ScrollbarLayerImplBase::OverlayScrollbarOpacity() const {
  return Opacity();
}

bool ScrollbarLayerImplBase::SupportsDragSnapBack() const {
  return false;
}

gfx::Rect ScrollbarLayerImplBase::BackButtonRect() const {
  return gfx::Rect(0, 0);
}

gfx::Rect ScrollbarLayerImplBase::ForwardButtonRect() const {
  return gfx::Rect(0, 0);
}

gfx::Rect ScrollbarLayerImplBase::BackTrackRect() const {
  return gfx::Rect(0, 0);
}

gfx::Rect ScrollbarLayerImplBase::ForwardTrackRect() const {
  return gfx::Rect(0, 0);
}

// This manages identifying which part of a composited scrollbar got hit based
// on the position_in_widget.
ScrollbarPart ScrollbarLayerImplBase::IdentifyScrollbarPart(
    const gfx::PointF position_in_widget) const {
  const gfx::Point pointer_location(position_in_widget.x(),
                                    position_in_widget.y());
  if (BackButtonRect().Contains(pointer_location))
    return ScrollbarPart::BACK_BUTTON;

  if (ForwardButtonRect().Contains(pointer_location))
    return ScrollbarPart::FORWARD_BUTTON;

  if (ComputeThumbQuadRect().Contains(pointer_location))
    return ScrollbarPart::THUMB;

  if (BackTrackRect().Contains(pointer_location))
    return ScrollbarPart::BACK_TRACK;

  if (ForwardTrackRect().Contains(pointer_location))
    return ScrollbarPart::FORWARD_TRACK;

  // TODO(arakeri): Once crbug.com/952314 is fixed, add a DCHECK to verify that
  // the point that is passed in is within the TrackRect. Also, please note that
  // hit testing other scrollbar parts is not yet implemented.
  return ScrollbarPart::NO_PART;
}

}  // namespace cc


text:
package com.myapos.clientmanager;

import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

/**
 * @author Myron Apostolakis
 */
// tag::code[]
@Component
@EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {

	static final String MESSAGE_PREFIX = "/topic";

	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		registry.addEndpoint("/clientmanager").withSockJS();
	}

	@Override
	public void configureMessageBroker(MessageBrokerRegistry registry) {
		registry.enableSimpleBroker(MESSAGE_PREFIX);
		registry.setApplicationDestinationPrefixes("/app");
	}
}
// end::code[]


text:
function y = deriv_over_x(this, x)
%DERIV_OVER_X   Evaluate derivative of robust function divided by argument
%   DERIV_OVER_X(THIS, X) evaluates the derivative of robustfunction THIS
%   divided by its argument at point(s) X.
%
%   This is a member function of the class 'robust_function'.
%
%   Author:  Stefan Roth, Department of Computer Science, TU Darmstadt
%   Contact: sroth@cs.tu-darmstadt.de
%   $Date:  $
%   $Revision: $

% Copyright 2004-2007, Brown University, Providence, RI. USA
% Copyright 2007-2010 TU Darmstadt, Darmstadt, Germany.
%
%                          All Rights Reserved
%
% All commercial use of this software, whether direct or indirect, is
% strictly prohibited including, without limitation, incorporation into in
% a commercial product, use in a commercial service, or production of other
% artifacts for commercial purposes.
%
% Permission to use, copy, modify, and distribute this software and its
% documentation for research purposes is hereby granted without fee,
% provided that the above copyright notice appears in all copies and that
% both that copyright notice and this permission notice appear in
% supporting documentation, and that the name of the author and Brown
% University not be used in advertising or publicity pertaining to
% distribution of the software without specific, written prior permission.
%
% For commercial uses contact the Technology Venture Office of Brown University
%
% THE AUTHOR AND BROWN UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO
% THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
% FITNESS FOR ANY PARTICULAR PURPOSE.  IN NO EVENT SHALL THE AUTHOR OR
% BROWN UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
% DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
% PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
% ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
% THIS SOFTWARE.

  y = feval(this.type, x, this.param, 2);


text:
<?xml version="1.0"?>
<psalm
    errorLevel="3"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="https://getpsalm.org/schema/config"
    xsi:schemaLocation="https://getpsalm.org/schema/config ../../vendor/vimeo/psalm/config.xsd"
>
    <projectFiles>
        <ignoreFiles>
            <file name="src/Task/ParallelExec.php" />
            <file name="src/Task/NonParallelExecV0.php" />
            <file name="src/Task/NonParallelExecV1.php" />
            <file name="src/Task/RoboAdapter.php" />
        </ignoreFiles>
    </projectFiles>

    <issueHandlers>
        <!-- phpqa specifics (multiple versions, compatibility classes, dynamic tools, ...) -->
        <UnusedClass>
            <errorLevel type="info">
                <directory name="tests" />
                <directory name="src/Tools/Analyzer" />
                <directory name="src/Task" />
                <file name="RoboFile.php" />
            </errorLevel>
        </UnusedClass>
        <PossiblyUnusedMethod>
            <errorLevel type="info">
                <file name="src/CodeAnalysisTasks.php" />
                <file name="src/RunningTool.php" />
            </errorLevel>
        </PossiblyUnusedMethod>
        <PossiblyInvalidArgument>
            <errorLevel type="info">
                <file name="src/paths.php" />
            </errorLevel>
        </PossiblyInvalidArgument>
        <PossiblyInvalidCast>
            <errorLevel type="info">
                <file name="src/paths.php" />
            </errorLevel>
        </PossiblyInvalidCast>
        <ArgumentTypeCoercion errorLevel="info" />
        <PropertyTypeCoercion errorLevel="info" />
        <PossiblyFalseOperand errorLevel="info" />
        <UndefinedConstant errorLevel="info" />
        <UndefinedClass errorLevel="info" />
        <UndefinedMethod errorLevel="info" />
        <InvalidArrayOffset errorLevel="info" />
        <InvalidFunctionCall errorLevel="info" />
        <InvalidReturnType errorLevel="info" />
        <ReservedWord errorLevel="info" />

        <!-- false positive -->
        <TooManyArguments>
            <errorLevel type="info">
                <directory name="tests" /><!-- Too many arguments for Prophecy -->
            </errorLevel>
        </TooManyArguments>
    </issueHandlers>
</psalm>


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<TITLE>
gov.nih.nci.cbiit.cmts.cda
</TITLE>

<META NAME="date" CONTENT="2012-04-16">

<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../../stylesheet.css" TITLE="Style">

gov.nih.nci.cbiit.cmts.cda

Classes

CDADatatypeParser

CDADatatypeParserUtil

NewCDABasicNodeLoader


text:
/*
Provides a map that can be used in a protected and concurrent fashion.
Map key must be a string, but the data can be anything.

Let's start by first getting a new map and adding a few new things to it.
You must get a map by using the New() function, and can add things to it using
Set(Key, Value):

	pm := protectedmap.New()
	pm.Set("one", 1)
	pm.Set("two", 2)

Now we can access our data through the Get function:

	data := pm.Get("one")

*/
package protectedmap

import (
	"sync"
)

// A map structure that stores data in a protected manner
type ProtectedMap struct {
	data map[string]interface{}
	lock sync.RWMutex
}

// Create a new protected map object
func New() ProtectedMap {
	return ProtectedMap{
		data: make(map[string]interface{}),
	}
}

// Add an object onto the map
func (m *ProtectedMap) Set(key string, value interface{}) {
	m.lock.Lock()
	m.data[key] = value
	m.lock.Unlock()
}

// Get a specific object out of the map.  In the event the key does not exist or
// the data is out of range, the function will have a second return of false.
//
// Get data:
// 	data, ok := pm.Get("mykey")
//
// Test if key exists:
// 	if _, ok := om.Get("mykey"); ok {
// 		... DO SOMETHING HERE ...
// 	}
func (m ProtectedMap) Get(key string) (interface{}, bool) {
	m.lock.RLock()
	data, ok := m.data[key]
	m.lock.RUnlock()
	return data, ok
}

// Delete a specific key and all associated data from the map
func (m *ProtectedMap) Delete(key string) {
	m.lock.Lock()
	delete(m.data, key)
	m.lock.Unlock()
}

// Get the total size of the map
func (m ProtectedMap) Count() int {
	m.lock.RLock()
	cnt := len(m.data)
	m.lock.RUnlock()
	return cnt
}

// A struct used to provide the ability to loop through all items in the map
type ProtectedMapIterator struct {
	returnchan chan Tuple
	breakchan  chan bool
	data       *ProtectedMap
}

// A data structure to hold returned information on each iteration
type Tuple struct {
	Key string
	Val interface{}
}

// Returns an ProtectedMapIterator type that can be used to loop through the
// entire map.
//
// This function will return a struct with two functions that should be used
// to iterate through the map: Loop() and Break().  Loop() should be provided
// to range and will return a Tuple for each item in the map.
//
// IMPORTANT NOTE: You must use the Break() function before you use the break
// go command, otherwise you might have deadlock, race, or garbage issues.
func (m *ProtectedMap) Iterator() ProtectedMapIterator {
	return ProtectedMapIterator{
		returnchan: make(chan Tuple),
		breakchan:  make(chan bool),
		data:       m,
	}
}

// Provides access to a channel that will allow looping through the entire
// map.  Returns a channel that can be passed to range and returns a
// Tuple struct with the key and value of each item.
//
// 	iter = mymap.Iterator()
// 	for data := range iter.Loop() {
// 		fmt.Printf("%s > %v\n", data.Key, data.Val)
// 	}
func (it *ProtectedMapIterator) Loop() <-chan Tuple {
	go func() {
		for k, v := range it.data.data {
			select {
			case it.returnchan <- Tuple{k, v}:
			case <-it.breakchan:
				close(it.returnchan)
				return
			}
		}

		close(it.returnchan)
		close(it.breakchan)
	}()

	return it.returnchan
}

// Signals the iterator that you no longer want to loop, allowing us to clean
// up, stop looping, and allows the garbage collector to clean up.  Finally,
// also makes sure all channels are closed and all mutex locks are clean, so
// that there are no issues with deadlocks.
func (it *ProtectedMapIterator) Break() {
	select {
	case _, _ = <-it.breakchan:
	default:
		it.breakchan <- true
	}
}


text:
require 'test_helper'

class SidebarEntriesHelperTest < ActionView::TestCase
end


text:
Meteor methods
===

Understanding meteor methods. Using Future for simulation remote API calls.

Article about this: [http://meteor.hromnik.com/blog/meteor-methods-and-remote-api-calls](http://meteor.hromnik.com/blog/meteor-methods-and-remote-api-calls)

Example: [http://meteor-methods.meteor.com/](http://meteor-methods.meteor.com/)


text:
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DragonSpark.Application.Entities.Queries.Compiled.Evaluation;

sealed class ToSum : IEvaluate<decimal, decimal>
{
	public static ToSum Default { get; } = new();

	ToSum() {}

	public ValueTask<decimal> Get(IAsyncEnumerable<decimal> parameter) => parameter.SumAsync();
}


text:
#if DEBUG
using ASC.Common.Web;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ASC.Common.Tests.Web {

	[TestClass]
	public class MimeMappingTest {

		[TestMethod]
		public void GetExtentionTest() {
			var ext = MimeMapping.GetExtention("application/x-zip-compressed");
			Assert.AreEqual(".zip", ext);

			ext = MimeMapping.GetExtention("Application/x-zip-Compressed");
			Assert.AreEqual(".zip", ext);

			ext = MimeMapping.GetExtention("Application/ZIP");
			Assert.AreEqual(".zip", ext);
		}
	}
}
#endif


text:
package me.yifeiyuan.climb.module.web;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;

import butterknife.Bind;
import me.yifeiyuan.climb.R;
import me.yifeiyuan.climb.base.BaseActivity;
import me.yifeiyuan.climb.ui.view.OpWebView;
import me.yifeiyuan.climb.ui.widget.ToastUtil;

public class WebActivity extends BaseActivity {

    private static final String KEY_URL = "key_url";

    @Bind(R.id.webview)
    OpWebView mWebview;

    @Bind(R.id.progress)
    ProgressBar mProgressBar;
    private String mUrl;

    public static void comeOn(Context context, String url) {
        Intent intent = new Intent(context, WebActivity.class);
        intent.putExtra(KEY_URL, url);
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
        // TODO: 16/11/30 加一个配置
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
            intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
//        }
        context.startActivity(intent);
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_web;
    }

    @Override
    protected void initData() {
        mUrl = getIntent().getStringExtra(KEY_URL);
        //如果是 github 的仓库地址,那么直接进完整的README 不然每次都要自己点
        if (mUrl.startsWith("https://github.com") && !mUrl.endsWith("README.md")) {
            mUrl = mUrl + "/blob/master/README.md";
        }
    }

    @Override
    protected void initView(Bundle savedInstanceState) {

        mWebview.setCallback(new OpWebView.Callback() {
            @Override
            public void onProgressChanged(int newProgress) {

                if (null == mProgressBar) {
                    return;
                }
                if (newProgress == 100) {
                    mProgressBar.setVisibility(View.GONE);
                } else {
                    mProgressBar.setProgress(newProgress);
                    mProgressBar.setVisibility(View.VISIBLE);
                }
            }

            @Override
            public void onReceivedTitle(String title) {
                setTitle(title);
            }

            @Override
            public void onPageFinished(String url) {
                mProgressBar.setVisibility(View.GONE);
            }
        });

        mWebview.loadUrl(mUrl);

    }

    @Override
    public void onBackPressed() {
        if (mWebview.canGoBack()) {
            mWebview.goBack();
        } else {
            super.onBackPressed();
        }
    }

    @Override
    protected void onDestroy() {
        ((ViewGroup)mWebview.getParent()).removeView(mWebview);
        mWebview.removeAllViews();
        mWebview.destroy();
        mWebview = null;
        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.web_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        int id = item.getItemId();
        switch (id) {

            case R.id.open:
                Intent i = new Intent(Intent.ACTION_VIEW);
                Uri uri = Uri.parse(mUrl);
                i.setData(uri);
                if (i.resolveActivity(getPackageManager()) != null) {
                    startActivity(Intent.createChooser(i,"请选择浏览器"));
                }
                break;

            case R.id.share:
                Intent share = new Intent(Intent.ACTION_SEND);
                share.setType("text/plain");
                share.putExtra(Intent.EXTRA_TEXT, mWebview.getUrl());
                startActivity(Intent.createChooser(share,"分享当前链接给"));
                break;

            case R.id.collect:
                ToastUtil.show(mContext,"Coming ");
                break;

            case R.id.copy_link:
                ClipboardManager manager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
                manager.setPrimaryClip(ClipData.newPlainText("URL",mUrl));
                ToastUtil.show(mContext,"Url复制成功");
                break;
        }
        return super.onOptionsItemSelected(item);
    }
}


text:
if(WIN32)
  set(INSTALL_DEPS_DEFAULT ON)
else(WIN32)
  set(INSTALL_DEPS_DEFAULT OFF)
endif(WIN32)

if(APPLE)
  set(Install_Dependencies OFF)
else(APPLE)
  option(Install_Dependencies
         "Install linked libraries with application"
         ${INSTALL_DEPS_DEFAULT})
endif(APPLE)

macro(find_and_install_dependencies EXEC_NAME)
  if(Install_Dependencies)

    set (APP "$<TARGET_FILE:${EXEC_NAME}>")
    set (GLOB_DIR "$<TARGET_FILE_DIR:${EXEC_NAME}>/*${CMAKE_SHARED_LIBRARY_SUFFIX}")

    add_custom_command(TARGET
                       ${EXEC_NAME}
                       POST_BUILD
                       COMMAND "${CMAKE_COMMAND}"
                       -D APP="${APP}"
                       -D CMAKE_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}"
                       -D BIN_DIR="${CMAKE_BINARY_DIR}"
                       -D CMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}"
                       -D GDAL_LIBDIR="${GDAL_LIBDIR}"
                       -D Qt5_DIR="${Qt5_DIR}"
                       -D OSG_DIR="${OSG_DIR}"
                       -P "${CMAKE_SOURCE_DIR}/misc/CMake/runBundleUtil.cmake"
                       )

    # Find files found by BundleUtilities and install them

    file(GLOB BUNDLED_LIBS "${GLOB_DIR}")
    foreach(FILE ${BUNDLED_LIBS})
      message(STATUS "adding ${FILE} to build directory")
      INSTALL(FILES "${FILE}" DESTINATION "${RUNTIME_DIR}")
    endforeach()
  endif(Install_Dependencies)
endmacro(find_and_install_dependencies)


text:
#include "core/css/StyleSheetContents.h"

#include "core/css/CSSStyleSheet.h"
#include "core/css/StylePropertySet.h"
#include "core/css/StyleRule.h"
#include "core/css/StyleRuleImport.h"
#include "core/css/StyleRuleNamespace.h"
#include "core/css/parser/CSSParser.h"
#include "core/dom/Document.h"
#include "core/dom/Node.h"
#include "core/dom/StyleEngine.h"
#include "core/fetch/CSSStyleSheetResource.h"
#include "core/frame/UseCounter.h"
#include "core/inspector/InspectorTraceEvents.h"
#include "platform/TraceEvent.h"
#include "platform/weborigin/SecurityOrigin.h"

namespace blink {

// Rough size estimate for the memory cache.
unsigned StyleSheetContents::estimatedSizeInBytes() const
{
    // Note that this does not take into account size of the strings hanging from various objects.
    // The assumption is that nearly all of of them are atomic and would exist anyway.
    unsigned size = sizeof(*this);

    // FIXME: This ignores the children of media rules.
    // Most rules are StyleRules.
    size += ruleCount() * StyleRule::averageSizeInBytes();

    for (unsigned i = 0; i < m_importRules.size(); ++i) {
        if (StyleSheetContents* sheet = m_importRules[i]->styleSheet())
            size += sheet->estimatedSizeInBytes();
    }
    return size;
}

StyleSheetContents::StyleSheetContents(StyleRuleImport* ownerRule, const String& originalURL, const CSSParserContext& context)
    : m_ownerRule(ownerRule)
    , m_originalURL(originalURL)
    , m_defaultNamespace(starAtom)
    , m_hasSyntacticallyValidCSSHeader(true)
    , m_didLoadErrorOccur(false)
    , m_isMutable(false)
    , m_hasFontFaceRule(false)
    , m_hasMediaQueries(false)
    , m_hasSingleOwnerDocument(true)
    , m_parserContext(context)
{
}

StyleSheetContents::StyleSheetContents(const StyleSheetContents& o)
    : m_ownerRule(nullptr)
    , m_originalURL(o.m_originalURL)
    , m_importRules(o.m_importRules.size())
    , m_namespaceRules(o.m_namespaceRules.size())
    , m_childRules(o.m_childRules.size())
    , m_namespaces(o.m_namespaces)
    , m_defaultNamespace(o.m_defaultNamespace)
    , m_hasSyntacticallyValidCSSHeader(o.m_hasSyntacticallyValidCSSHeader)
    , m_didLoadErrorOccur(false)
    , m_isMutable(false)
    , m_hasFontFaceRule(o.m_hasFontFaceRule)
    , m_hasMediaQueries(o.m_hasMediaQueries)
    , m_hasSingleOwnerDocument(true)
    , m_parserContext(o.m_parserContext)
{
    // FIXME: Copy import rules.
    ASSERT(o.m_importRules.isEmpty());

    for (unsigned i = 0; i < m_childRules.size(); ++i)
        m_childRules[i] = o.m_childRules[i]->copy();
}

StyleSheetContents::~StyleSheetContents()
{
}

void StyleSheetContents::setHasSyntacticallyValidCSSHeader(bool isValidCss)
{
    if (!isValidCss) {
        if (Document* document = clientSingleOwnerDocument())
            removeSheetFromCache(document);
    }
    m_hasSyntacticallyValidCSSHeader = isValidCss;
}

bool StyleSheetContents::isCacheableForResource() const
{
    // This would require dealing with multiple clients for load callbacks.
    if (!loadCompleted())
        return false;
    // FIXME: StyleSheets with media queries can't be cached because their RuleSet
    // is processed differently based off the media queries, which might resolve
    // differently depending on the context of the parent CSSStyleSheet (e.g.
    // if they are in differently sized iframes). Once RuleSets are media query
    // agnostic, we can restore sharing of StyleSheetContents with medea queries.
    if (m_hasMediaQueries)
        return false;
    // FIXME: Support copying import rules.
    if (!m_importRules.isEmpty())
        return false;
    // FIXME: Support cached stylesheets in import rules.
    if (m_ownerRule)
        return false;
    if (m_didLoadErrorOccur)
        return false;
    // It is not the original sheet anymore.
    if (m_isMutable)
        return false;
    // If the header is valid we are not going to need to check the SecurityOrigin.
    // FIXME: Valid mime type avoids the check too.
    if (!m_hasSyntacticallyValidCSSHeader)
        return false;
    return true;
}

bool StyleSheetContents::isCacheableForStyleElement() const
{
    // FIXME: Support copying import rules.
    if (!importRules().isEmpty())
        return false;
    // Until import rules are supported in cached sheets it's not possible for loading to fail.
    DCHECK(!didLoadErrorOccur());
    // It is not the original sheet anymore.
    if (isMutable())
        return false;
    if (!hasSyntacticallyValidCSSHeader())
        return false;
    return true;
}

void StyleSheetContents::parserAppendRule(StyleRuleBase* rule)
{
    if (rule->isImportRule()) {
        // Parser enforces that @import rules come before anything else
        ASSERT(m_childRules.isEmpty());
        StyleRuleImport* importRule = toStyleRuleImport(rule);
        if (importRule->mediaQueries())
            setHasMediaQueries();
        m_importRules.append(importRule);
        m_importRules.last()->setParentStyleSheet(this);
        m_importRules.last()->requestStyleSheet();
        return;
    }

    if (rule->isNamespaceRule()) {
        // Parser enforces that @namespace rules come before all rules other than
        // import/charset rules
        ASSERT(m_childRules.isEmpty());
        StyleRuleNamespace& namespaceRule = toStyleRuleNamespace(*rule);
        parserAddNamespace(namespaceRule.prefix(), namespaceRule.uri());
        m_namespaceRules.append(&namespaceRule);
        return;
    }

    if (rule->isMediaRule())
        setHasMediaQueries();

    m_childRules.append(rule);
}

void StyleSheetContents::setHasMediaQueries()
{
    m_hasMediaQueries = true;
    if (parentStyleSheet())
        parentStyleSheet()->setHasMediaQueries();
}

StyleRuleBase* StyleSheetContents::ruleAt(unsigned index) const
{
    ASSERT_WITH_SECURITY_IMPLICATION(index < ruleCount());

    if (index < m_importRules.size())
        return m_importRules[index].get();

    index -= m_importRules.size();

    if (index < m_namespaceRules.size())
        return m_namespaceRules[index].get();

    index -= m_namespaceRules.size();

    return m_childRules[index].get();
}

unsigned StyleSheetContents::ruleCount() const
{
    return m_importRules.size() + m_namespaceRules.size() + m_childRules.size();
}

void StyleSheetContents::clearRules()
{
    for (unsigned i = 0; i < m_importRules.size(); ++i) {
        ASSERT(m_importRules.at(i)->parentStyleSheet() == this);
        m_importRules[i]->clearParentStyleSheet();
    }
    m_importRules.clear();
    m_namespaceRules.clear();
    m_childRules.clear();
}

bool StyleSheetContents::wrapperInsertRule(StyleRuleBase* rule, unsigned index)
{
    ASSERT(m_isMutable);
    ASSERT_WITH_SECURITY_IMPLICATION(index <= ruleCount());

    if (index < m_importRules.size() || (index == m_importRules.size() && rule->isImportRule())) {
        // Inserting non-import rule before @import is not allowed.
        if (!rule->isImportRule())
            return false;

        StyleRuleImport* importRule = toStyleRuleImport(rule);
        if (importRule->mediaQueries())
            setHasMediaQueries();

        m_importRules.insert(index, importRule);
        m_importRules[index]->setParentStyleSheet(this);
        m_importRules[index]->requestStyleSheet();
        // FIXME: Stylesheet doesn't actually change meaningfully before the imported sheets are loaded.
        return true;
    }
    // Inserting @import rule after a non-import rule is not allowed.
    if (rule->isImportRule())
        return false;

    index -= m_importRules.size();

    if (index < m_namespaceRules.size() || (index == m_namespaceRules.size() && rule->isNamespaceRule())) {
        // Inserting non-namespace rules other than import rule before @namespace is not allowed.
        if (!rule->isNamespaceRule())
            return false;
        // Inserting @namespace rule when rules other than import/namespace/charset are present is not allowed.
        if (!m_childRules.isEmpty())
            return false;

        StyleRuleNamespace* namespaceRule = toStyleRuleNamespace(rule);
        m_namespaceRules.insert(index, namespaceRule);
        // For now to be compatible with IE and Firefox if namespace rule with same prefix is added
        // irrespective of adding the rule at any index, last added rule's value is considered.
        // TODO (ramya.v@samsung.com): As per spec last valid rule should be considered,
        // which means if namespace rule is added in the middle of existing namespace rules,
        // rule which comes later in rule list with same prefix needs to be considered.
        parserAddNamespace(namespaceRule->prefix(), namespaceRule->uri());
        return true;
    }

    if (rule->isNamespaceRule())
        return false;

    index -= m_namespaceRules.size();

    if (rule->isMediaRule())
        setHasMediaQueries();
    else if (rule->isFontFaceRule())
        setHasFontFaceRule(true);

    m_childRules.insert(index, rule);
    return true;
}

bool StyleSheetContents::wrapperDeleteRule(unsigned index)
{
    ASSERT(m_isMutable);
    ASSERT_WITH_SECURITY_IMPLICATION(index < ruleCount());

    if (index < m_importRules.size()) {
        m_importRules[index]->clearParentStyleSheet();
        if (m_importRules[index]->isFontFaceRule())
            notifyRemoveFontFaceRule(toStyleRuleFontFace(m_importRules[index].get()));
        m_importRules.remove(index);
        return true;
    }
    index -= m_importRules.size();

    if (index < m_namespaceRules.size()) {
        if (!m_childRules.isEmpty())
            return false;
        m_namespaceRules.remove(index);
        return true;
    }
    index -= m_namespaceRules.size();

    if (m_childRules[index]->isFontFaceRule())
        notifyRemoveFontFaceRule(toStyleRuleFontFace(m_childRules[index].get()));
    m_childRules.remove(index);
    return true;
}

void StyleSheetContents::parserAddNamespace(const AtomicString& prefix, const AtomicString& uri)
{
    ASSERT(!uri.isNull());
    if (prefix.isNull()) {
        m_defaultNamespace = uri;
        return;
    }
    PrefixNamespaceURIMap::AddResult result = m_namespaces.add(prefix, uri);
    if (result.isNewEntry)
        return;
    result.storedValue->value = uri;
}

const AtomicString& StyleSheetContents::namespaceURIFromPrefix(const AtomicString& prefix)
{
    return m_namespaces.get(prefix);
}

void StyleSheetContents::parseAuthorStyleSheet(const CSSStyleSheetResource* cachedStyleSheet, const SecurityOrigin* securityOrigin)
{
    TRACE_EVENT1("blink,devtools.timeline", "ParseAuthorStyleSheet", "data", InspectorParseAuthorStyleSheetEvent::data(cachedStyleSheet));

    bool isSameOriginRequest = securityOrigin && securityOrigin->canRequest(baseURL());

    // When the response was fetched via the Service Worker, the original URL may not be same as the base URL.
    // TODO(horo): When we will use the original URL as the base URL, we can remove this check. crbug.com/553535
    if (cachedStyleSheet->response().wasFetchedViaServiceWorker()) {
        const KURL originalURL(cachedStyleSheet->response().originalURLViaServiceWorker());
        // |originalURL| is empty when the response is created in the SW.
        if (!originalURL.isEmpty() && !securityOrigin->canRequest(originalURL))
            isSameOriginRequest = false;
    }

    CSSStyleSheetResource::MIMETypeCheck mimeTypeCheck = isQuirksModeBehavior(m_parserContext.mode()) && isSameOriginRequest ? CSSStyleSheetResource::MIMETypeCheck::Lax : CSSStyleSheetResource::MIMETypeCheck::Strict;
    String sheetText = cachedStyleSheet->sheetText(mimeTypeCheck);

    const ResourceResponse& response = cachedStyleSheet->response();
    m_sourceMapURL = response.httpHeaderField(HTTPNames::SourceMap);
    if (m_sourceMapURL.isEmpty()) {
        // Try to get deprecated header.
        m_sourceMapURL = response.httpHeaderField(HTTPNames::X_SourceMap);
    }

    CSSParserContext context(parserContext(), UseCounter::getFrom(this));
    CSSParser::parseSheet(context, this, sheetText);
}

void StyleSheetContents::parseString(const String& sheetText)
{
    parseStringAtPosition(sheetText, TextPosition::minimumPosition());
}

void StyleSheetContents::parseStringAtPosition(const String& sheetText, const TextPosition& startPosition)
{
    CSSParserContext context(parserContext(), UseCounter::getFrom(this));
    CSSParser::parseSheet(context, this, sheetText);
}

bool StyleSheetContents::isLoading() const
{
    for (unsigned i = 0; i < m_importRules.size(); ++i) {
        if (m_importRules[i]->isLoading())
            return true;
    }
    return false;
}

bool StyleSheetContents::loadCompleted() const
{
    StyleSheetContents* parentSheet = parentStyleSheet();
    if (parentSheet)
        return parentSheet->loadCompleted();

    StyleSheetContents* root = rootStyleSheet();
    return root->m_loadingClients.isEmpty();
}

void StyleSheetContents::checkLoaded()
{
    if (isLoading())
        return;

    StyleSheetContents* parentSheet = parentStyleSheet();
    if (parentSheet) {
        parentSheet->checkLoaded();
        return;
    }

    ASSERT(this == rootStyleSheet());
    if (m_loadingClients.isEmpty())
        return;

    // Avoid |CSSSStyleSheet| and |ownerNode| being deleted by scripts that run via
    // ScriptableDocumentParser::executeScriptsWaitingForResources(). Also protect
    // the |CSSStyleSheet| from being deleted during iteration via the |sheetLoaded|
    // method.
    //
    // When a sheet is loaded it is moved from the set of loading clients
    // to the set of completed clients. We therefore need the copy in order to
    // not modify the set while iterating it.
    HeapVector<Member<CSSStyleSheet>> loadingClients;
    copyToVector(m_loadingClients, loadingClients);

    for (unsigned i = 0; i < loadingClients.size(); ++i) {
        if (loadingClients[i]->loadCompleted())
            continue;

        // sheetLoaded might be invoked after its owner node is removed from document.
        if (Node* ownerNode = loadingClients[i]->ownerNode()) {
            if (loadingClients[i]->sheetLoaded())
                ownerNode->notifyLoadedSheetAndAllCriticalSubresources(m_didLoadErrorOccur ? Node::ErrorOccurredLoadingSubresource : Node::NoErrorLoadingSubresource);
        }
    }
}

void StyleSheetContents::notifyLoadedSheet(const CSSStyleSheetResource* sheet)
{
    ASSERT(sheet);
    m_didLoadErrorOccur |= sheet->errorOccurred();
    // updateLayoutIgnorePendingStyleSheets can cause us to create the RuleSet on this
    // sheet before its imports have loaded. So clear the RuleSet when the imports
    // load since the import's subrules are flattened into its parent sheet's RuleSet.
    clearRuleSet();
}

void StyleSheetContents::startLoadingDynamicSheet()
{
    StyleSheetContents* root = rootStyleSheet();
    for (const auto& client : root->m_loadingClients)
        client->startLoadingDynamicSheet();
    // Copy the completed clients to a vector for iteration.
    // startLoadingDynamicSheet will move the style sheet from the
    // completed state to the loading state which modifies the set of
    // completed clients. We therefore need the copy in order to not
    // modify the set of completed clients while iterating it.
    HeapVector<Member<CSSStyleSheet>> completedClients;
    copyToVector(root->m_completedClients, completedClients);
    for (unsigned i = 0; i < completedClients.size(); ++i)
        completedClients[i]->startLoadingDynamicSheet();
}

StyleSheetContents* StyleSheetContents::rootStyleSheet() const
{
    const StyleSheetContents* root = this;
    while (root->parentStyleSheet())
        root = root->parentStyleSheet();
    return const_cast<StyleSheetContents*>(root);
}

bool StyleSheetContents::hasSingleOwnerNode() const
{
    return rootStyleSheet()->hasOneClient();
}

Node* StyleSheetContents::singleOwnerNode() const
{
    StyleSheetContents* root = rootStyleSheet();
    if (!root->hasOneClient())
        return nullptr;
    if (root->m_loadingClients.size())
        return (*root->m_loadingClients.begin())->ownerNode();
    return (*root->m_completedClients.begin())->ownerNode();
}

Document* StyleSheetContents::singleOwnerDocument() const
{
    StyleSheetContents* root = rootStyleSheet();
    return root->clientSingleOwnerDocument();
}

static bool childRulesHaveFailedOrCanceledSubresources(const HeapVector<Member<StyleRuleBase>>& rules)
{
    for (unsigned i = 0; i < rules.size(); ++i) {
        const StyleRuleBase* rule = rules[i].get();
        switch (rule->type()) {
        case StyleRuleBase::Style:
            if (toStyleRule(rule)->properties().hasFailedOrCanceledSubresources())
                return true;
            break;
        case StyleRuleBase::FontFace:
            if (toStyleRuleFontFace(rule)->properties().hasFailedOrCanceledSubresources())
                return true;
            break;
        case StyleRuleBase::Media:
            if (childRulesHaveFailedOrCanceledSubresources(toStyleRuleMedia(rule)->childRules()))
                return true;
            break;
        case StyleRuleBase::Charset:
        case StyleRuleBase::Import:
        case StyleRuleBase::Namespace:
            ASSERT_NOT_REACHED();
        case StyleRuleBase::Page:
        case StyleRuleBase::Keyframes:
        case StyleRuleBase::Keyframe:
        case StyleRuleBase::Supports:
        case StyleRuleBase::Viewport:
            break;
        }
    }
    return false;
}

bool StyleSheetContents::hasFailedOrCanceledSubresources() const
{
    ASSERT(isCacheableForResource());
    return childRulesHaveFailedOrCanceledSubresources(m_childRules);
}

Document* StyleSheetContents::clientSingleOwnerDocument() const
{
    if (!m_hasSingleOwnerDocument || clientSize() <= 0)
        return nullptr;

    if (m_loadingClients.size())
        return (*m_loadingClients.begin())->ownerDocument();
    return (*m_completedClients.begin())->ownerDocument();
}

StyleSheetContents* StyleSheetContents::parentStyleSheet() const
{
    return m_ownerRule ? m_ownerRule->parentStyleSheet() : nullptr;
}

void StyleSheetContents::registerClient(CSSStyleSheet* sheet)
{
    ASSERT(!m_loadingClients.contains(sheet) && !m_completedClients.contains(sheet));

    // InspectorCSSAgent::buildObjectForRule creates CSSStyleSheet without any owner node.
    if (!sheet->ownerDocument())
        return;

    if (Document* document = clientSingleOwnerDocument()) {
        if (sheet->ownerDocument() != document)
            m_hasSingleOwnerDocument = false;
    }
    m_loadingClients.add(sheet);
}

void StyleSheetContents::unregisterClient(CSSStyleSheet* sheet)
{
    m_loadingClients.remove(sheet);
    m_completedClients.remove(sheet);

    if (!sheet->ownerDocument() || !m_loadingClients.isEmpty() || !m_completedClients.isEmpty())
        return;

    if (m_hasSingleOwnerDocument)
        removeSheetFromCache(sheet->ownerDocument());
    m_hasSingleOwnerDocument = true;
}

void StyleSheetContents::clientLoadCompleted(CSSStyleSheet* sheet)
{
    ASSERT(m_loadingClients.contains(sheet) || !sheet->ownerDocument());
    m_loadingClients.remove(sheet);
    // In m_ownerNode->sheetLoaded, the CSSStyleSheet might be detached.
    // (i.e. clearOwnerNode was invoked.)
    // In this case, we don't need to add the stylesheet to completed clients.
    if (!sheet->ownerDocument())
        return;
    m_completedClients.add(sheet);
}

void StyleSheetContents::clientLoadStarted(CSSStyleSheet* sheet)
{
    ASSERT(m_completedClients.contains(sheet));
    m_completedClients.remove(sheet);
    m_loadingClients.add(sheet);
}

void StyleSheetContents::removeSheetFromCache(Document* document)
{
    ASSERT(document);
    document->styleEngine().removeSheet(this);
}

void StyleSheetContents::setReferencedFromResource(CSSStyleSheetResource* resource)
{
    DCHECK(resource);
    DCHECK(!isReferencedFromResource());
    DCHECK(isCacheableForResource());
    m_referencedFromResource = resource;
}

void StyleSheetContents::clearReferencedFromResource()
{
    DCHECK(isReferencedFromResource());
    DCHECK(isCacheableForResource());
    m_referencedFromResource = nullptr;
}

RuleSet& StyleSheetContents::ensureRuleSet(const MediaQueryEvaluator& medium, AddRuleFlags addRuleFlags)
{
    if (!m_ruleSet) {
        m_ruleSet = RuleSet::create();
        m_ruleSet->addRulesFromSheet(this, medium, addRuleFlags);
    }
    return *m_ruleSet.get();
}

static void clearResolvers(HeapHashSet<WeakMember<CSSStyleSheet>>& clients)
{
    for (const auto& sheet : clients) {
        if (Document* document = sheet->ownerDocument())
            document->styleEngine().clearResolver();
    }
}

void StyleSheetContents::clearRuleSet()
{
    if (StyleSheetContents* parentSheet = parentStyleSheet())
        parentSheet->clearRuleSet();

    // Don't want to clear the StyleResolver if the RuleSet hasn't been created
    // since we only clear the StyleResolver so that it's members are properly
    // updated in ScopedStyleResolver::addRulesFromSheet.
    if (!m_ruleSet)
        return;

    // Clearing the ruleSet means we need to recreate the styleResolver data structures.
    // See the StyleResolver calls in ScopedStyleResolver::addRulesFromSheet.
    clearResolvers(m_loadingClients);
    clearResolvers(m_completedClients);
    m_ruleSet.clear();
}

static void removeFontFaceRules(HeapHashSet<WeakMember<CSSStyleSheet>>& clients, const StyleRuleFontFace* fontFaceRule)
{
    for (const auto& sheet : clients) {
        if (Node* ownerNode = sheet->ownerNode())
            ownerNode->document().styleEngine().removeFontFaceRules(HeapVector<Member<const StyleRuleFontFace>>(1, fontFaceRule));
    }
}

void StyleSheetContents::notifyRemoveFontFaceRule(const StyleRuleFontFace* fontFaceRule)
{
    StyleSheetContents* root = rootStyleSheet();
    removeFontFaceRules(root->m_loadingClients, fontFaceRule);
    removeFontFaceRules(root->m_completedClients, fontFaceRule);
}

static void findFontFaceRulesFromRules(const HeapVector<Member<StyleRuleBase>>& rules, HeapVector<Member<const StyleRuleFontFace>>& fontFaceRules)
{
    for (unsigned i = 0; i < rules.size(); ++i) {
        StyleRuleBase* rule = rules[i].get();

        if (rule->isFontFaceRule()) {
            fontFaceRules.append(toStyleRuleFontFace(rule));
        } else if (rule->isMediaRule()) {
            StyleRuleMedia* mediaRule = toStyleRuleMedia(rule);
            // We cannot know whether the media rule matches or not, but
            // for safety, remove @font-face in the media rule (if exists).
            findFontFaceRulesFromRules(mediaRule->childRules(), fontFaceRules);
        }
    }
}

void StyleSheetContents::findFontFaceRules(HeapVector<Member<const StyleRuleFontFace>>& fontFaceRules)
{
    for (unsigned i = 0; i < m_importRules.size(); ++i) {
        if (!m_importRules[i]->styleSheet())
            continue;
        m_importRules[i]->styleSheet()->findFontFaceRules(fontFaceRules);
    }

    findFontFaceRulesFromRules(childRules(), fontFaceRules);
}

DEFINE_TRACE(StyleSheetContents)
{
    visitor->trace(m_ownerRule);
    visitor->trace(m_importRules);
    visitor->trace(m_namespaceRules);
    visitor->trace(m_childRules);
    visitor->trace(m_loadingClients);
    visitor->trace(m_completedClients);
    visitor->trace(m_ruleSet);
    visitor->trace(m_referencedFromResource);
}

} // namespace blink


text:
package com.example.yuyu.mylogger;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

import java.util.HashMap;
import java.util.Map;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.ordinary:
                printOrdinaryStr();
                break;
            case R.id.json:
                printJson();
                break;
            case R.id.map:
                printMap();
                break;
            case R.id.default_log:
                printSystemDefaultLog();
                break;
        }
    }

    private void printSystemDefaultLog(){
        L.d(TAG, "系统默认格式");
    }

    private void printOrdinaryStr() {
        L.d("带详情信息的Log");
    }

    private void printJson() {
        String json = "{\"name\":\"tom\",\"sex\":\"男\",\"age\":\"24\", \"list\":[1,2,3,4,5],\"end\":\"最后一个\"}";
        L.j(json);
    }

    private void printMap() {
        Map<String, String> map = new HashMap<>();
        for (int i = 0; i < 10; i++){
            map.put("key " + i, "value " + i);
        }
        L.m(map);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}


text:
set -e

lib="${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"
nm ${lib} > /dev/null  # Just make sure this works.

pattern="${1}"

if [ $pattern != "a|b" ]; then
  echo "Parameter quoting is broken"
  exit 1
fi

if [ "${2}" != "arg with spaces" ]; then
  echo "Parameter space escaping is broken"
  exit 1
fi

touch "${lib}"_touch


text:
#ifndef _ES2AACCURACYTESTS_HPP
#define _ES2AACCURACYTESTS_HPP
/*!
 * \file
 * \brief Accuracy tests.
 *//*--------------------------------------------------------------------*/

#include "tcuDefs.hpp"
#include "tes2TestCase.hpp"

namespace deqp
{
namespace gles2
{
namespace Accuracy
{

class AccuracyTests : public TestCaseGroup
{
public:
						AccuracyTests		(Context& context);
						~AccuracyTests		(void);

	void				init				(void);

private:
						AccuracyTests		(const AccuracyTests& other);
	AccuracyTests&		operator=			(const AccuracyTests& other);
};

} // Accuracy
} // gles2
} // deqp

#endif // _ES2AACCURACYTESTS_HPP


text:
package norbert.mynemo.dataimport.fileformat.output;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.IOException;

import norbert.mynemo.dataimport.fileformat.MynemoRating;
import norbert.mynemo.dataimport.scraping.input.CkScraper;

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

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;

/**
 * This filter writes all ratings except the ratings already written. Two ratings are considered
 * equal if their users are equal and their movies are equals. The values are not taken in account.
 */
public class DuplicateRemover implements RatingWriter {

  private static final Logger LOGGER = LoggerFactory.getLogger(CkScraper.class);

  private final RatingWriter nextWriter;
  /** Ratings already written. A key is a user, a value is one of its rated movie. */
  private final Multimap<String, String> unwritableRatings;

  public DuplicateRemover(final RatingWriter nextWriter) {
    checkNotNull(nextWriter);

    this.nextWriter = nextWriter;
    unwritableRatings = HashMultimap.create();
  }

  @Override
  public void close() throws IOException {
    unwritableRatings.clear();
    nextWriter.close();
  }

  @Override
  public void write(final MynemoRating rating) throws IOException {
    checkNotNull(rating);

    final String user = rating.getUser();
    final String movie = rating.getMovie();

    if (!unwritableRatings.containsEntry(user, movie)) {
      unwritableRatings.put(user, movie);
      nextWriter.write(rating);
    } else {
      LOGGER.warn("A duplicate rating is detected: {} has rated {} more than once.", user, movie);
    }
  }
}